Fossil Forum

Fossil crashes with import --git importing Bazaar repositories [Patches included]
Login

Fossil crashes with import --git importing Bazaar repositories [Patches included]

(1.4) By Thomas Hess (luziferius) on 2020-11-13 14:06:51 edited from 1.3 [source]

I’m back with more issues with the git importer when used to import Bazaar repositories ;)

First, I got a segmentation fault when I tried to import a dump of one of my projects. I did a bisect on the commit causing this [*], then I grabbed the debugger and found that it was caused by a rename (R entry in fast-import format), more specifically this line, which occurs 2 times in import.c:

pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]);

Afaik, %s takes a char*, but the third parameter returns a char, thus trying to dereference a pointer somewhere in the range [0-255]. Because no-one reported this, it looks like git actually never emits "R " and "C " entries.

Second, the executable bit of executables is lost, because Bazaar uses a slightly different format to convey file permissions (3 instead of 6 digits for regular files).

Third, the import fails, if the user used the rebase plugin for Bazaar, because the export actually contains information about the rebase, in the form of property rebase-of entries in the file.
I simply ignore them in the importer, as the original information is lost after the rebase. It seems to denote from where a commit was moved by the rebase.
(I used the plugin to correct commit messages and correct unwanted forking caused by brz not having an auto-sync feature, at least none that I’m aware of.
Thank you for providing the possibility to edit commit messages in fossil after a push already happened, this is a really cool feature.)

All three issues are patched in the linked branch of my repository copy here:

http://1337net.duckdns.org:8080/fossil/timeline?r=fix-import-git-with-bazaar

There is a fourth issue: The code doesn’t actually track renamed files, thus breaking the history across renames.
I assume the renames should be in the list of renames (like this page: https://fossil-scm.org/fossil/test-rename-list, but in my repository), but it is actually empty after the import finishes. I’m investigating, but am a bit lost at the moment.

[*] You can export a commit range by running brz fast-export -r 1-10 to export the first 10 commits of the exported branch.

Edit: I’ve appended individual Patches

Segfault:

Index: src/import.c
==================================================================
--- src/import.c
+++ src/import.c
@@ -752,11 +752,11 @@
       while( (pFile = import_find_file(zFrom, &i, mx))!=0 ){
         if( pFile->isFrom==0 ) continue;
         pNew = import_add_file();
         pFile = &gg.aFile[i-1];
         if( strlen(pFile->zName)>nFrom ){
-          pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]);
+          pNew->zName = mprintf("%s%s", zTo, &pFile->zName[nFrom]);
         }else{
           pNew->zName = fossil_strdup(zTo);
         }
         pNew->isExe = pFile->isExe;
         pNew->isLink = pFile->isLink;
@@ -775,11 +775,11 @@
       while( (pFile = import_find_file(zFrom, &i, gg.nFile))!=0 ){
         if( pFile->isFrom==0 ) continue;
         pNew = import_add_file();
         pFile = &gg.aFile[i-1];
         if( strlen(pFile->zName)>nFrom ){
-          pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]);
+          pNew->zName = mprintf("%s%s", zTo, &pFile->zName[nFrom]);
         }else{
           pNew->zName = fossil_strdup(zTo);
         }
         pNew->zPrior = pFile->zName;
         pNew->isExe = pFile->isExe;

Executable bit:

Index: src/import.c
==================================================================
--- src/import.c
+++ src/import.c
@@ -712,11 +712,13 @@
       pFile = import_find_file(zName, &i, gg.nFile);
       if( pFile==0 ){
         pFile = import_add_file();
         pFile->zName = fossil_strdup(zName);
       }
-      pFile->isExe = (fossil_strcmp(zPerm, "100755")==0);
+      /* Git uses 6-digit permission masks, Bazaar uses 3-digit masks for regular files.
+      ** Compare the last 3 digits. */
+      pFile->isExe = (fossil_strcmp(&zPerm[strlen(zPerm)-3], "755")==0);
       pFile->isLink = (fossil_strcmp(zPerm, "120000")==0);
       fossil_free(pFile->zUuid);
       if( strcmp(zUuid,"inline")==0 ){
         pFile->zUuid = 0;
         gg.pInlineFile = pFile;

Handling property rebase-of:

Index: src/import.c
==================================================================
--- src/import.c
+++ src/import.c
@@ -805,10 +805,16 @@
       ** user-readable branch name. */
       z = &zLine[21];
       next_token(&z);
       fossil_free(gg.zBranch);
       gg.zBranch = fossil_strdup(next_token(&z));
+    }else
+    if ( strncmp(zLine, "property rebase-of ", 19)==0 ){
+      /* Breezy uses this property to store the fact that
+      ** a commit was part of a rebase. This only occurs
+      ** when the user used the Bazaar rebase plugin. */
+      /* Currently No-op */
     }else
     {
       goto malformed_line;
     }
   }