Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -113,10 +113,18 @@ blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName); }else if( isChnged==4 ){ blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName); }else if( isChnged==5 ){ blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName); + }else if( isChnged==6 ){ + blob_appendf(report, "EXECUTABLE %s\n", zDisplayName); + }else if( isChnged==7 ){ + blob_appendf(report, "SYMLINK %s\n", zDisplayName); + }else if( isChnged==8 ){ + blob_appendf(report, "UNEXEC %s\n", zDisplayName); + }else if( isChnged==9 ){ + blob_appendf(report, "UNLINK %s\n", zDisplayName); }else if( file_contains_merge_marker(zFullName) ){ blob_appendf(report, "CONFLICT %s\n", zDisplayName); }else{ blob_appendf(report, "EDITED %s\n", zDisplayName); } @@ -1633,10 +1641,12 @@ int dryRunFlag; /* True for a test run. Debugging only */ CheckinInfo sCiInfo; /* Information about this check-in */ const char *zComFile; /* Read commit message from this file */ int nTag = 0; /* Number of --tag arguments */ const char *zTag; /* A single --tag argument */ + ManifestFile *pFile; /* File structure in the manifest */ + Manifest *pManifest; /* Manifest structure */ Blob manifest; /* Manifest in baseline form */ Blob muuid; /* Manifest uuid */ Blob cksum1, cksum2; /* Before and after commit checksums */ Blob cksum1b; /* Checksum recorded in the manifest */ int szD; /* Size of the delta manifest */ @@ -2070,11 +2080,10 @@ blob_write_to_file(&muuid, zManifestFile); free(zManifestFile); blob_reset(&muuid); } - /* Update the vfile and vmerge tables */ db_multi_exec( "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);" "DELETE FROM vmerge;" "UPDATE vfile SET vid=%d;" @@ -2081,10 +2090,28 @@ "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL" " WHERE is_selected(id);" , vid, nvid ); db_lset_int("checkout", nvid); + + /* Update the isexe and islink columns of the vfile table */ + db_prepare(&q, + "UPDATE vfile SET isexe=:exec, islink=:link" + " WHERE vid=:vid AND pathname=:path AND (isexe!=:exec OR islink!=:link)" + ); + db_bind_int(&q, ":vid", nvid); + pManifest = manifest_get(nvid, CFTYPE_MANIFEST, 0); + manifest_file_rewind(pManifest); + while( (pFile = manifest_file_next(pManifest, 0)) ){ + db_bind_int(&q, ":exec", pFile->zPerm && strstr(pFile->zPerm, "x")); + db_bind_int(&q, ":link", pFile->zPerm && strstr(pFile->zPerm, "l")); + db_bind_text(&q, ":path", pFile->zName); + db_step(&q); + db_reset(&q); + } + db_finalize(&q); + manifest_destroy(pManifest); if( useCksum ){ /* Verify that the repository checksum matches the expected checksum ** calculated before the check-in started (and stored as the R record ** of the manifest file). Index: src/vfile.c ================================================================== --- src/vfile.c +++ src/vfile.c @@ -136,15 +136,22 @@ #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */ #endif /* INTERFACE */ /* -** Look at every VFILE entry with the given vid and update -** VFILE.CHNGED field according to whether or not -** the file has changed. 0 means no change. 1 means edited. 2 means -** the file has changed due to a merge. 3 means the file was added -** by a merge. +** Look at every VFILE entry with the given vid and update VFILE.CHNGED field +** according to whether or not the file has changed. +** - 0 means no change. +** - 1 means edited. +** - 2 means changed due to a merge. +** - 3 means added by a merge. +** - 4 means changed due to an integrate merge. +** - 5 means added by an integrate merge. +** - 6 means became executable but has unmodified contents. +** - 7 means became a symlink whose target equals its old contents. +** - 8 means lost executable status but has unmodified contents. +** - 9 means lost symlink status and has contents equal to its old target. ** ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either ** removed from configuration management via "fossil rm" or added via ** "fossil add", respectively, and in both cases we always know that ** the file has changed without having the check the size, mtime, @@ -170,18 +177,22 @@ int useMtime = (cksigFlags & CKSIG_SHA1)==0 && db_get_boolean("mtime-changes", 1); db_begin_transaction(); db_prepare(&q, "SELECT id, %Q || pathname," - " vfile.mrid, deleted, chnged, uuid, size, mtime" + " vfile.mrid, deleted, chnged, uuid, size, mtime," + " CASE WHEN isexe THEN %d WHEN islink THEN %d ELSE %d END" " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" - " WHERE vid=%d ", g.zLocalRoot, vid); + " WHERE vid=%d ", g.zLocalRoot, PERM_EXE, PERM_LNK, PERM_REG, + vid); while( db_step(&q)==SQLITE_ROW ){ int id, rid, isDeleted; const char *zName; int chnged = 0; int oldChnged; + int origPerm; + int currentPerm; i64 oldMtime; i64 currentMtime; i64 origSize; i64 currentSize; @@ -192,10 +203,12 @@ oldChnged = chnged = db_column_int(&q, 4); oldMtime = db_column_int64(&q, 7); origSize = db_column_int64(&q, 6); currentSize = file_wd_size(zName); currentMtime = file_wd_mtime(0); + origPerm = db_column_int(&q, 8); + currentPerm = file_wd_perm(zName); if( chnged==0 && (isDeleted || rid==0) ){ /* "fossil rm" or "fossil add" always change the file */ chnged = 1; }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){ if( cksigFlags & CKSIG_ENOTFILE ){ @@ -245,10 +258,25 @@ file_set_mtime(zName, desiredMtime); currentMtime = file_wd_mtime(zName); } } } +#ifndef _WIN32 + if( chnged==0 || chnged==6 || chnged==7 || chnged==8 || chnged==9 ){ + if( origPerm == currentPerm ){ + chnged = 0; + }else if( currentPerm == PERM_EXE ){ + chnged = 6; + }else if( currentPerm == PERM_LNK ){ + chnged = 7; + }else if( origPerm == PERM_EXE ){ + chnged = 8; + }else if( origPerm == PERM_LNK ){ + chnged = 9; + } + } +#endif if( currentMtime!=oldMtime || chnged!=oldChnged ){ db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d", currentMtime, chnged, id); } } Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -30,14 +30,17 @@ leaves on the same branch. * Added the "Blitz" skin option. * Removed the ".fossil-settings/keep-glob" file. It should not have been checked into the repository. * Update the built-in SQLite to version 3.8.10.1. - * Made [/help?cmd=open|fossil open] honor ".fossil-settings/allow-symlinks". + * Make [/help?cmd=open|fossil open] honor ".fossil-settings/allow-symlinks". * Allow [/help?cmd=add|fossil add] to be used on symlinks to nonexistent or unreadable files in the same way as [/help?cmd=addremove|fossil addremove]. * Added fork warning to be issued if sync produced a fork + * Have [/help/cmd=changes|fossil changes] and + [/help/cmd=status|fossil status] report when executable or symlink status + changes on otherwise unmodified files.

Changes for Version 1.32 (2015-03-14)

* When creating a new repository using [/help?cmd=init|fossil init], ensure that the new repository is fully compatible with historical versions of Fossil by having a valid manifest as RID 1.