int _tmain(int argc, _TCHAR* argv[]) { // we have three parameters const TCHAR* src = nullptr; const TCHAR* dst = nullptr; const TCHAR* wc = nullptr; BOOL bErrResursively = FALSE; BOOL bErrOnMods = FALSE; BOOL bErrOnUnversioned = FALSE; BOOL bQuiet = FALSE; GitWCRev_t GitStat; SetDllDirectory(L""); CCrashReportTGit crasher(L"GitWCRev " _T(APP_X64_STRING), TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE); if (argc >= 2 && argc <= 5) { // WC path is always first argument. wc = argv[1]; } if (argc == 4 || argc == 5) { // GitWCRev Path Tmpl.in Tmpl.out [-params] src = argv[2]; dst = argv[3]; if (!PathFileExists(src)) { _tprintf(L"File '%s' does not exist\n", src); return ERR_FNF; // file does not exist } } if (argc == 3 || argc == 5) { // GitWCRev Path -params // GitWCRev Path Tmpl.in Tmpl.out -params const TCHAR* Params = argv[argc - 1]; if (Params[0] == L'-') { if (wcschr(Params, L'e') != 0) _setmode(_fileno(stdout), _O_U16TEXT); if (wcschr(Params, L'q') != 0) bQuiet = TRUE; if (wcschr(Params, L'm') != 0) bErrOnMods = TRUE; if (wcschr(Params, L'u') != 0) bErrOnUnversioned = TRUE; if (wcschr(Params, L'M') != 0) { bErrOnMods = TRUE; bErrResursively = TRUE; } if (wcschr(Params, L'U') != 0) { bErrOnUnversioned = TRUE; bErrResursively = TRUE; } if (wcschr(Params, L'd') != 0) { if (dst && PathFileExists(dst)) { _tprintf(L"File '%s' already exists\n", dst); return ERR_OUT_EXISTS; } } if (wcschr(Params, L's') != 0) GitStat.bNoSubmodules = TRUE; } else { // Bad params - abort and display help. wc = nullptr; } } if (!wc) { _tprintf(L"GitWCRev %d.%d.%d, Build %d - %s\n\n", TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, _T(TGIT_PLATFORM)); _putts(_T(HelpText1)); _putts(_T(HelpText2)); _putts(_T(HelpText3)); _putts(_T(HelpText4)); _putts(_T(HelpText5)); return ERR_SYNTAX; } DWORD reqLen = GetFullPathName(wc, 0, nullptr, nullptr); auto wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(wc, reqLen, wcfullPath.get(), nullptr); // GetFullPathName() sometimes returns the full path with the wrong // case. This is not a problem on Windows since its filesystem is // case-insensitive. But for Git that's a problem if the wrong case // is inside a working copy: the git index is case sensitive. // To fix the casing of the path, we use a trick: // convert the path to its short form, then back to its long form. // That will fix the wrong casing of the path. int shortlen = GetShortPathName(wcfullPath.get(), nullptr, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(wcfullPath.get(), shortPath.get(), shortlen + 1)) { reqLen = GetLongPathName(shortPath.get(), nullptr, 0); wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), wcfullPath.get(), reqLen); } } wc = wcfullPath.get(); std::unique_ptr<TCHAR[]> dstfullPath; if (dst) { reqLen = GetFullPathName(dst, 0, nullptr, nullptr); dstfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(dst, reqLen, dstfullPath.get(), nullptr); shortlen = GetShortPathName(dstfullPath.get(), nullptr, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(dstfullPath.get(), shortPath.get(), shortlen+1)) { reqLen = GetLongPathName(shortPath.get(), nullptr, 0); dstfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), dstfullPath.get(), reqLen); } } dst = dstfullPath.get(); } std::unique_ptr<TCHAR[]> srcfullPath; if (src) { reqLen = GetFullPathName(src, 0, nullptr, nullptr); srcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(src, reqLen, srcfullPath.get(), nullptr); shortlen = GetShortPathName(srcfullPath.get(), nullptr, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(srcfullPath.get(), shortPath.get(), shortlen+1)) { reqLen = GetLongPathName(shortPath.get(), nullptr, 0); srcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), srcfullPath.get(), reqLen); } } src = srcfullPath.get(); } if (!PathFileExists(wc)) { _tprintf(L"Directory or file '%s' does not exist\n", wc); if (wcschr(wc, '\"')) // dir contains a quotation mark { _tprintf(L"The WorkingCopyPath contains a quotation mark.\n"); _tprintf(L"this indicates a problem when calling GitWCRev from an interpreter which treats\n"); _tprintf(L"a backslash char specially.\n"); _tprintf(L"Try using double backslashes or insert a dot after the last backslash when\n"); _tprintf(L"calling GitWCRev\n"); _tprintf(L"Examples:\n"); _tprintf(L"GitWCRev \"path to wc\\\\\"\n"); _tprintf(L"GitWCRev \"path to wc\\.\"\n"); } return ERR_FNF; // dir does not exist } std::unique_ptr<char[]> pBuf; DWORD readlength = 0; size_t filelength = 0; size_t maxlength = 0; if (dst) { // open the file and read the contents CAutoFile hFile = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0); if (!hFile) { _tprintf(L"Unable to open input file '%s'\n", src); return ERR_OPEN; // error opening file } filelength = GetFileSize(hFile, nullptr); if (filelength == INVALID_FILE_SIZE) { _tprintf(L"Could not determine file size of '%s'\n", src); return ERR_READ; } maxlength = filelength + 8192; // We might be increasing file size. pBuf = std::make_unique<char[]>(maxlength); if (!pBuf) { _tprintf(L"Could not allocate enough memory!\n"); return ERR_ALLOC; } if (!ReadFile(hFile, pBuf.get(), (DWORD)filelength, &readlength, nullptr)) { _tprintf(L"Could not read the file '%s'\n", src); return ERR_READ; } if (readlength != filelength) { _tprintf(L"Could not read the file '%s' to the end!\n", src); return ERR_READ; } } git_libgit2_init(); // Now check the status of every file in the working copy // and gather revision status information in GitStat. int err = GetStatus(wc, GitStat); git_libgit2_shutdown(); if (err) return err; if (!bQuiet) { char wcfull_oem[MAX_PATH] = { 0 }; CharToOem(wc, wcfull_oem); _tprintf(L"GitWCRev: '%hs'\n", wcfull_oem); } if (bErrOnMods && (GitStat.HasMods || GitStat.bHasSubmoduleNewCommits || (bErrResursively && GitStat.bHasSubmoduleMods))) { if (!bQuiet) _tprintf(L"Working tree has uncomitted modifications!\n"); return ERR_GIT_MODS; } if (bErrOnUnversioned && (GitStat.HasUnversioned || (bErrResursively && GitStat.bHasSubmoduleUnversioned))) { if (!bQuiet) _tprintf(L"Working tree has unversioned items!\n"); return ERR_GIT_UNVER; } if (!bQuiet) { _tprintf(L"HEAD is %s\n", CUnicodeUtils::StdGetUnicode(GitStat.HeadHashReadable).c_str()); if (GitStat.HasMods) _tprintf(L"Uncommitted modifications found\n"); if (GitStat.HasUnversioned) _tprintf(L"Unversioned items found\n"); } if (!dst) return 0; // now parse the file contents for version defines. size_t index = 0; while (InsertRevision(VERDEF, pBuf.get(), index, filelength, maxlength, &GitStat)); index = 0; while (InsertRevisionW(TEXT(VERDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, &GitStat)); index = 0; while (InsertRevision(VERDEFSHORT, pBuf.get(), index, filelength, maxlength, &GitStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFSHORT), (wchar_t*)pBuf.get(), index, filelength, maxlength, &GitStat)); index = 0; while (InsertDate(DATEDEF, pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDateW(TEXT(DATEDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDate(DATEDEFUTC, pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDateW(TEXT(DATEDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDate(DATEWFMTDEF, pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDateW(TEXT(DATEWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDate(DATEWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDateW(TEXT(DATEWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.HeadTime)); index = 0; while (InsertDate(NOWDEF, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWDEFUTC, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWWFMTDEF, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertBoolean(MODDEF, pBuf.get(), index, filelength, GitStat.HasMods || GitStat.bHasSubmoduleNewCommits)); index = 0; while (InsertBooleanW(TEXT(MODDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.HasMods || GitStat.bHasSubmoduleNewCommits)); index = 0; while (InsertBoolean(UNVERDEF, pBuf.get(), index, filelength, GitStat.HasUnversioned)); index = 0; while (InsertBooleanW(TEXT(UNVERDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.HasUnversioned)); index = 0; while (InsertBoolean(ISTAGGED, pBuf.get(), index, filelength, GitStat.bIsTagged)); index = 0; while (InsertBooleanW(TEXT(ISTAGGED), (wchar_t*)pBuf.get(), index, filelength, GitStat.bIsTagged)); index = 0; while (InsertBoolean(ISINGIT, pBuf.get(), index, filelength, GitStat.bIsGitItem)); index = 0; while (InsertBooleanW(TEXT(ISINGIT), (wchar_t*)pBuf.get(), index, filelength, GitStat.bIsGitItem)); index = 0; while (InsertBoolean(SUBDEF, pBuf.get(), index, filelength, GitStat.bHasSubmodule)); index = 0; while (InsertBooleanW(TEXT(SUBDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.bHasSubmodule)); index = 0; while (InsertBoolean(SUBUP2DATEDEF, pBuf.get(), index, filelength, !GitStat.bHasSubmoduleNewCommits)); index = 0; while (InsertBooleanW(TEXT(SUBUP2DATEDEF), (wchar_t*)pBuf.get(), index, filelength, !GitStat.bHasSubmoduleNewCommits)); index = 0; while (InsertBoolean(MODINSUBDEF, pBuf.get(), index, filelength, GitStat.bHasSubmoduleMods)); index = 0; while (InsertBooleanW(TEXT(MODINSUBDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.bHasSubmoduleMods)); index = 0; while (InsertBoolean(UNVERINSUBDEF, pBuf.get(), index, filelength, GitStat.bHasSubmoduleUnversioned)); index = 0; while (InsertBooleanW(TEXT(UNVERINSUBDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.bHasSubmoduleUnversioned)); index = 0; while (InsertBoolean(UNVERFULLDEF, pBuf.get(), index, filelength, GitStat.HasUnversioned || GitStat.bHasSubmoduleUnversioned)); index = 0; while (InsertBooleanW(TEXT(UNVERFULLDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.HasUnversioned || GitStat.bHasSubmoduleUnversioned)); index = 0; while (InsertBoolean(MODFULLDEF, pBuf.get(), index, filelength, GitStat.HasMods || GitStat.bHasSubmoduleMods || GitStat.bHasSubmoduleUnversioned)); index = 0; while (InsertBooleanW(TEXT(MODFULLDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.HasMods || GitStat.bHasSubmoduleMods || GitStat.bHasSubmoduleUnversioned)); index = 0; while (InsertBoolean(MODSFILEDEF, pBuf.get(), index, filelength, GitStat.HasMods)); index = 0; while (InsertBooleanW(TEXT(MODSFILEDEF), (wchar_t*)pBuf.get(), index, filelength, GitStat.HasMods)); index = 0; while (InsertNumber(VALDEF, pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumberW(TEXT(VALDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumber(VALDEFAND, pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumberW(TEXT(VALDEFAND), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumber(VALDEFOFFSET1, pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumberW(TEXT(VALDEFOFFSET1), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumber(VALDEFOFFSET2, pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertNumberW(TEXT(VALDEFOFFSET2), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.NumCommits)); index = 0; while (InsertText(BRANCHDEF, pBuf.get(), index, filelength, maxlength, GitStat.CurrentBranch)); index = 0; while (InsertTextW(TEXT(BRANCHDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, GitStat.CurrentBranch)); CAutoFile hFile = CreateFile(dst, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, 0, 0); if (!hFile) { _tprintf(L"Unable to open output file '%s' for writing\n", dst); return ERR_OPEN; } size_t filelengthExisting = GetFileSize(hFile, nullptr); BOOL sameFileContent = FALSE; if (filelength == filelengthExisting) { DWORD readlengthExisting = 0; auto pBufExisting = std::make_unique<char[]>(filelength); if (!ReadFile(hFile, pBufExisting.get(), (DWORD)filelengthExisting, &readlengthExisting, nullptr)) { _tprintf(L"Could not read the file '%s'\n", dst); return ERR_READ; } if (readlengthExisting != filelengthExisting) { _tprintf(L"Could not read the file '%s' to the end!\n", dst); return ERR_READ; } sameFileContent = (memcmp(pBuf.get(), pBufExisting.get(), filelength) == 0); } // The file is only written if its contents would change. // this object prevents the timestamp from changing. if (!sameFileContent) { SetFilePointer(hFile, 0, nullptr, FILE_BEGIN); WriteFile(hFile, pBuf.get(), (DWORD)filelength, &readlength, nullptr); if (readlength != filelength) { _tprintf(L"Could not write the file '%s' to the end!\n", dst); return ERR_READ; } if (!SetEndOfFile(hFile)) { _tprintf(L"Could not truncate the file '%s' to the end!\n", dst); return ERR_READ; } } return 0; }
int _tmain(int argc, _TCHAR* argv[]) { // we have three parameters const TCHAR * src = NULL; const TCHAR * dst = NULL; const TCHAR * wc = NULL; BOOL bErrOnMods = FALSE; BOOL bErrOnUnversioned = FALSE; BOOL bErrOnMixed = FALSE; BOOL bQuiet = FALSE; BOOL bUseSubWCRevIgnore = TRUE; SubWCRev_t SubStat; SetDllDirectory(L""); CCrashReportTSVN crasher(L"SubWCRev " _T(APP_X64_STRING)); if (argc >= 2 && argc <= 5) { // WC path is always first argument. wc = argv[1]; } if (argc == 4 || argc == 5) { // SubWCRev Path Tmpl.in Tmpl.out [-params] src = argv[2]; dst = argv[3]; if (!PathFileExists(src)) { _tprintf(L"File '%s' does not exist\n", src); return ERR_FNF; // file does not exist } } if (argc == 3 || argc == 5) { // SubWCRev Path -params // SubWCRev Path Tmpl.in Tmpl.out -params const TCHAR * Params = argv[argc-1]; if (Params[0] == '-') { if (wcschr(Params, 'q') != 0) bQuiet = TRUE; if (wcschr(Params, 'n') != 0) bErrOnMods = TRUE; if (wcschr(Params, 'N') != 0) bErrOnUnversioned = TRUE; if (wcschr(Params, 'm') != 0) bErrOnMixed = TRUE; if (wcschr(Params, 'd') != 0) { if ((dst != NULL) && PathFileExists(dst)) { _tprintf(L"File '%s' already exists\n", dst); return ERR_OUT_EXISTS; } } // the 'f' option is useful to keep the revision which is inserted in // the file constant, even if there are commits on other branches. // For example, if you tag your working copy, then half a year later // do a fresh checkout of that tag, the folder in your working copy of // that tag will get the HEAD revision of the time you check out (or // do an update). The files alone however won't have their last-committed // revision changed at all. if (wcschr(Params, 'f') != 0) SubStat.bFolders = TRUE; if (wcschr(Params, 'e') != 0) SubStat.bExternals = TRUE; if (wcschr(Params, 'E') != 0) SubStat.bExternalsNoMixedRevision = TRUE; if (wcschr(Params, 'x') != 0) SubStat.bHexPlain = TRUE; if (wcschr(Params, 'X') != 0) SubStat.bHexX = TRUE; if (wcschr(Params, 'F') != 0) bUseSubWCRevIgnore = FALSE; } else { // Bad params - abort and display help. wc = NULL; } } if (wc == NULL) { _tprintf(L"SubWCRev %d.%d.%d, Build %d - %s\n\n", TSVN_VERMAJOR, TSVN_VERMINOR, TSVN_VERMICRO, TSVN_VERBUILD, _T(TSVN_PLATFORM)); _putts(_T(HelpText1)); _putts(_T(HelpText2)); _putts(_T(HelpText3)); _putts(_T(HelpText4)); _putts(_T(HelpText5)); return ERR_SYNTAX; } DWORD reqLen = GetFullPathName(wc, 0, NULL, NULL); auto wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(wc, reqLen, wcfullPath.get(), NULL); // GetFullPathName() sometimes returns the full path with the wrong // case. This is not a problem on Windows since its filesystem is // case-insensitive. But for SVN that's a problem if the wrong case // is inside a working copy: the svn wc database is case sensitive. // To fix the casing of the path, we use a trick: // convert the path to its short form, then back to its long form. // That will fix the wrong casing of the path. int shortlen = GetShortPathName(wcfullPath.get(), NULL, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(wcfullPath.get(), shortPath.get(), shortlen + 1)) { reqLen = GetLongPathName(shortPath.get(), NULL, 0); wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), wcfullPath.get(), reqLen); } } wc = wcfullPath.get(); std::unique_ptr<TCHAR[]> dstfullPath = nullptr; if (dst) { reqLen = GetFullPathName(dst, 0, NULL, NULL); dstfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(dst, reqLen, dstfullPath.get(), NULL); shortlen = GetShortPathName(dstfullPath.get(), NULL, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(dstfullPath.get(), shortPath.get(), shortlen+1)) { reqLen = GetLongPathName(shortPath.get(), NULL, 0); dstfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), dstfullPath.get(), reqLen); } } dst = dstfullPath.get(); } std::unique_ptr<TCHAR[]> srcfullPath = nullptr; if (src) { reqLen = GetFullPathName(src, 0, NULL, NULL); srcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(src, reqLen, srcfullPath.get(), NULL); shortlen = GetShortPathName(srcfullPath.get(), NULL, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(srcfullPath.get(), shortPath.get(), shortlen+1)) { reqLen = GetLongPathName(shortPath.get(), NULL, 0); srcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), srcfullPath.get(), reqLen); } } src = srcfullPath.get(); } if (!PathFileExists(wc)) { _tprintf(L"Directory or file '%s' does not exist\n", wc); if (wcschr(wc, '\"') != NULL) // dir contains a quotation mark { _tprintf(L"The WorkingCopyPath contains a quotation mark.\n"); _tprintf(L"this indicates a problem when calling SubWCRev from an interpreter which treats\n"); _tprintf(L"a backslash char specially.\n"); _tprintf(L"Try using double backslashes or insert a dot after the last backslash when\n"); _tprintf(L"calling SubWCRev\n"); _tprintf(L"Examples:\n"); _tprintf(L"SubWCRev \"path to wc\\\\\"\n"); _tprintf(L"SubWCRev \"path to wc\\.\"\n"); } return ERR_FNF; // dir does not exist } std::unique_ptr<char[]> pBuf = nullptr; DWORD readlength = 0; size_t filelength = 0; size_t maxlength = 0; if (dst != NULL) { // open the file and read the contents CAutoFile hFile = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (!hFile) { _tprintf(L"Unable to open input file '%s'\n", src); return ERR_OPEN; // error opening file } filelength = GetFileSize(hFile, NULL); if (filelength == INVALID_FILE_SIZE) { _tprintf(L"Could not determine file size of '%s'\n", src); return ERR_READ; } maxlength = filelength+4096; // We might be increasing file size. pBuf = std::make_unique<char[]>(maxlength); if (pBuf == NULL) { _tprintf(L"Could not allocate enough memory!\n"); return ERR_ALLOC; } if (!ReadFile(hFile, pBuf.get(), (DWORD)filelength, &readlength, NULL)) { _tprintf(L"Could not read the file '%s'\n", src); return ERR_READ; } if (readlength != filelength) { _tprintf(L"Could not read the file '%s' to the end!\n", src); return ERR_READ; } } // Now check the status of every file in the working copy // and gather revision status information in SubStat. apr_pool_t * pool; svn_error_t * svnerr = NULL; svn_client_ctx_t * ctx; const char * internalpath; apr_initialize(); svn_dso_initialize2(); apr_pool_create_ex (&pool, NULL, abort_on_pool_failure, NULL); svn_client_create_context2(&ctx, NULL, pool); size_t ret = 0; getenv_s(&ret, NULL, 0, "SVN_ASP_DOT_NET_HACK"); if (ret) { svn_wc_set_adm_dir("_svn", pool); } char *wc_utf8 = Utf16ToUtf8(wc, pool); internalpath = svn_dirent_internal_style (wc_utf8, pool); if (bUseSubWCRevIgnore) { const char *wcroot; svnerr = svn_client_get_wc_root(&wcroot, internalpath, ctx, pool, pool); if ((svnerr == SVN_NO_ERROR) && wcroot) LoadIgnorePatterns(wcroot, &SubStat); svn_error_clear(svnerr); LoadIgnorePatterns(internalpath, &SubStat); } svnerr = svn_status( internalpath, //path &SubStat, //status_baton TRUE, //noignore ctx, pool); if (svnerr) { svn_handle_error2(svnerr, stdout, FALSE, "SubWCRev : "); } TCHAR wcfullpath[MAX_PATH] = { 0 }; LPTSTR dummy; GetFullPathName(wc, MAX_PATH, wcfullpath, &dummy); apr_status_t e = 0; if (svnerr) { e = svnerr->apr_err; svn_error_clear(svnerr); } apr_terminate2(); if (svnerr) { if (e == SVN_ERR_WC_NOT_DIRECTORY) return ERR_NOWC; return ERR_SVN_ERR; } char wcfull_oem[MAX_PATH] = { 0 }; CharToOem(wcfullpath, wcfull_oem); _tprintf(L"SubWCRev: '%hs'\n", wcfull_oem); if (bErrOnMods && SubStat.HasMods) { _tprintf(L"Working copy has local modifications!\n"); return ERR_SVN_MODS; } if (bErrOnUnversioned && SubStat.HasUnversioned) { _tprintf(L"Working copy has unversioned items!\n"); return ERR_SVN_UNVER; } if (bErrOnMixed && (SubStat.MinRev != SubStat.MaxRev)) { if (SubStat.bHexPlain) _tprintf(L"Working copy contains mixed revisions %lX:%lX!\n", SubStat.MinRev, SubStat.MaxRev); else if (SubStat.bHexX) _tprintf(L"Working copy contains mixed revisions %#lX:%#lX!\n", SubStat.MinRev, SubStat.MaxRev); else _tprintf(L"Working copy contains mixed revisions %ld:%ld!\n", SubStat.MinRev, SubStat.MaxRev); return ERR_SVN_MIXED; } if (!bQuiet) { if (SubStat.bHexPlain) _tprintf(L"Last committed at revision %lX\n", SubStat.CmtRev); else if (SubStat.bHexX) _tprintf(L"Last committed at revision %#lX\n", SubStat.CmtRev); else _tprintf(L"Last committed at revision %ld\n", SubStat.CmtRev); if (SubStat.MinRev != SubStat.MaxRev) { if (SubStat.bHexPlain) _tprintf(L"Mixed revision range %lX:%lX\n", SubStat.MinRev, SubStat.MaxRev); else if (SubStat.bHexX) _tprintf(L"Mixed revision range %#lX:%#lX\n", SubStat.MinRev, SubStat.MaxRev); else _tprintf(L"Mixed revision range %ld:%ld\n", SubStat.MinRev, SubStat.MaxRev); } else { if (SubStat.bHexPlain) _tprintf(L"Updated to revision %lX\n", SubStat.MaxRev); else if (SubStat.bHexX) _tprintf(L"Updated to revision %#lX\n", SubStat.MaxRev); else _tprintf(L"Updated to revision %ld\n", SubStat.MaxRev); } if (SubStat.HasMods) { _tprintf(L"Local modifications found\n"); } if (SubStat.HasUnversioned) { _tprintf(L"Unversioned items found\n"); } } if (dst == NULL) { return 0; } // now parse the file contents for version defines. size_t index = 0; while (InsertRevision(VERDEF, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(VERDEFAND, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFAND), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(VERDEFOFFSET1, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFOFFSET1), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(VERDEFOFFSET2, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFOFFSET2), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(RANGEDEF, pBuf.get(), index, filelength, maxlength, SubStat.MinRev, SubStat.MaxRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(RANGEDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.MinRev, SubStat.MaxRev, &SubStat)); index = 0; while (InsertDate(DATEDEF, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(DATEDEFUTC, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(DATEWFMTDEF, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(DATEWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(NOWDEF, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWDEFUTC, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWWFMTDEF, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertBoolean(MODDEF, pBuf.get(), index, filelength, SubStat.HasMods)); index = 0; while (InsertBooleanW(TEXT(MODDEF), (wchar_t*)pBuf.get(), index, filelength, SubStat.HasMods)); index = 0; while (InsertBoolean(UNVERDEF, pBuf.get(), index, filelength, SubStat.HasUnversioned)); index = 0; while (InsertBooleanW(TEXT(UNVERDEF), (wchar_t*)pBuf.get(), index, filelength, SubStat.HasUnversioned)); index = 0; while (InsertBoolean(MIXEDDEF, pBuf.get(), index, filelength, (SubStat.MinRev != SubStat.MaxRev) || SubStat.bIsExternalMixed)); index = 0; while (InsertBooleanW(TEXT(MIXEDDEF), (wchar_t*)pBuf.get(), index, filelength, (SubStat.MinRev != SubStat.MaxRev) || SubStat.bIsExternalMixed)); index = 0; while (InsertBoolean(EXTALLFIXED, pBuf.get(), index, filelength, !SubStat.bIsExternalsNotFixed)); index = 0; while (InsertBooleanW(TEXT(EXTALLFIXED), (wchar_t*)pBuf.get(), index, filelength, !SubStat.bIsExternalsNotFixed)); index = 0; while (InsertBoolean(ISTAGGED, pBuf.get(), index, filelength, SubStat.bIsTagged)); index = 0; while (InsertBooleanW(TEXT(ISTAGGED), (wchar_t*)pBuf.get(), index, filelength, SubStat.bIsTagged)); index = 0; while (InsertUrl(URLDEF, pBuf.get(), index, filelength, maxlength, SubStat.Url)); index = 0; while (InsertUrlW(TEXT(URLDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, Utf8ToWide(SubStat.Url).c_str())); index = 0; while (InsertBoolean(ISINSVN, pBuf.get(), index, filelength, SubStat.bIsSvnItem)); index = 0; while (InsertBooleanW(TEXT(ISINSVN), (wchar_t*)pBuf.get(), index, filelength, SubStat.bIsSvnItem)); index = 0; while (InsertBoolean(NEEDSLOCK, pBuf.get(), index, filelength, SubStat.LockData.NeedsLocks)); index = 0; while (InsertBooleanW(TEXT(NEEDSLOCK), (wchar_t*)pBuf.get(), index, filelength, SubStat.LockData.NeedsLocks)); index = 0; while (InsertBoolean(ISLOCKED, pBuf.get(), index, filelength, SubStat.LockData.IsLocked)); index = 0; while (InsertBooleanW(TEXT(ISLOCKED), (wchar_t*)pBuf.get(), index, filelength, SubStat.LockData.IsLocked)); index = 0; while (InsertDate(LOCKDATE, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKDATE), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDate(LOCKDATEUTC, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKDATEUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDate(LOCKWFMTDEF, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDate(LOCKWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertUrl(LOCKOWNER, pBuf.get(), index, filelength, maxlength, SubStat.LockData.Owner)); index = 0; while (InsertUrlW(TEXT(LOCKOWNER), (wchar_t*)pBuf.get(), index, filelength, maxlength, Utf8ToWide(SubStat.LockData.Owner).c_str())); index = 0; while (InsertUrl(LOCKCOMMENT, pBuf.get(), index, filelength, maxlength, SubStat.LockData.Comment)); index = 0; while (InsertUrlW(TEXT(LOCKCOMMENT), (wchar_t*)pBuf.get(), index, filelength, maxlength, Utf8ToWide(SubStat.LockData.Comment).c_str())); CAutoFile hFile = CreateFile(dst, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL); if (!hFile) { _tprintf(L"Unable to open output file '%s' for writing\n", dst); return ERR_OPEN; } size_t filelengthExisting = GetFileSize(hFile, NULL); BOOL sameFileContent = FALSE; if (filelength == filelengthExisting) { DWORD readlengthExisting = 0; auto pBufExisting = std::make_unique<char[]>(filelength); if (!ReadFile(hFile, pBufExisting.get(), (DWORD)filelengthExisting, &readlengthExisting, NULL)) { _tprintf(L"Could not read the file '%s'\n", dst); return ERR_READ; } if (readlengthExisting != filelengthExisting) { _tprintf(L"Could not read the file '%s' to the end!\n", dst); return ERR_READ; } sameFileContent = (memcmp(pBuf.get(), pBufExisting.get(), filelength) == 0); } // The file is only written if its contents would change. // this object prevents the timestamp from changing. if (!sameFileContent) { SetFilePointer(hFile, 0, NULL, FILE_BEGIN); WriteFile(hFile, pBuf.get(), (DWORD)filelength, &readlength, NULL); if (readlength != filelength) { _tprintf(L"Could not write the file '%s' to the end!\n", dst); return ERR_READ; } if (!SetEndOfFile(hFile)) { _tprintf(L"Could not truncate the file '%s' to the end!\n", dst); return ERR_READ; } } return 0; }