| | @@ -1049,10 +1049,22 @@ |
| 1049 | 1049 | db_exec(&s1); |
| 1050 | 1050 | fnid = db_last_insert_rowid(); |
| 1051 | 1051 | } |
| 1052 | 1052 | return fnid; |
| 1053 | 1053 | } |
| 1054 | + |
| 1055 | +/* |
| 1056 | +** Compute an appropriate mlink.mperm integer for the permission string |
| 1057 | +** of a file. |
| 1058 | +*/ |
| 1059 | +int manifest_file_mperm(ManifestFile *pFile){ |
| 1060 | + int mperm = 0; |
| 1061 | + if( pFile && pFile->zPerm && strstr(pFile->zPerm,"x")!=0 ){ |
| 1062 | + mperm = 1; |
| 1063 | + } |
| 1064 | + return mperm; |
| 1065 | +} |
| 1054 | 1066 | |
| 1055 | 1067 | /* |
| 1056 | 1068 | ** Add a single entry to the mlink table. Also add the filename to |
| 1057 | 1069 | ** the filename table if it is not there already. |
| 1058 | 1070 | */ |
| | @@ -1059,11 +1071,12 @@ |
| 1059 | 1071 | static void add_one_mlink( |
| 1060 | 1072 | int mid, /* The record ID of the manifest */ |
| 1061 | 1073 | const char *zFromUuid, /* UUID for the mlink.pid. "" to add file */ |
| 1062 | 1074 | const char *zToUuid, /* UUID for the mlink.fid. "" to delele */ |
| 1063 | 1075 | const char *zFilename, /* Filename */ |
| 1064 | | - const char *zPrior /* Previous filename. NULL if unchanged */ |
| 1076 | + const char *zPrior, /* Previous filename. NULL if unchanged */ |
| 1077 | + int mperm /* 1: exec */ |
| 1065 | 1078 | ){ |
| 1066 | 1079 | int fnid, pfnid, pid, fid; |
| 1067 | 1080 | static Stmt s1; |
| 1068 | 1081 | |
| 1069 | 1082 | fnid = filename_to_fnid(zFilename); |
| | @@ -1081,18 +1094,19 @@ |
| 1081 | 1094 | fid = 0; |
| 1082 | 1095 | }else{ |
| 1083 | 1096 | fid = uuid_to_rid(zToUuid, 1); |
| 1084 | 1097 | } |
| 1085 | 1098 | db_static_prepare(&s1, |
| 1086 | | - "INSERT INTO mlink(mid,pid,fid,fnid,pfnid)" |
| 1087 | | - "VALUES(:m,:p,:f,:n,:pfn)" |
| 1099 | + "INSERT INTO mlink(mid,pid,fid,fnid,pfnid,mperm)" |
| 1100 | + "VALUES(:m,:p,:f,:n,:pfn,:mp)" |
| 1088 | 1101 | ); |
| 1089 | 1102 | db_bind_int(&s1, ":m", mid); |
| 1090 | 1103 | db_bind_int(&s1, ":p", pid); |
| 1091 | 1104 | db_bind_int(&s1, ":f", fid); |
| 1092 | 1105 | db_bind_int(&s1, ":n", fnid); |
| 1093 | 1106 | db_bind_int(&s1, ":pfn", pfnid); |
| 1107 | + db_bind_int(&s1, ":mp", mperm); |
| 1094 | 1108 | db_exec(&s1); |
| 1095 | 1109 | if( pid && fid ){ |
| 1096 | 1110 | content_deltify(pid, fid, 0); |
| 1097 | 1111 | } |
| 1098 | 1112 | } |
| | @@ -1158,15 +1172,16 @@ |
| 1158 | 1172 | } |
| 1159 | 1173 | return pFile; |
| 1160 | 1174 | } |
| 1161 | 1175 | |
| 1162 | 1176 | /* |
| 1163 | | -** Add mlink table entries associated with manifest cid. The |
| 1164 | | -** parent manifest is pid. |
| 1177 | +** Add mlink table entries associated with manifest cid, pChild. The |
| 1178 | +** parent manifest is pid, pParent. One of either pChild or pParent |
| 1179 | +** will be NULL and it will be computed based on cid/pid. |
| 1165 | 1180 | ** |
| 1166 | | -** A single mlink entry is added for every file that changed content |
| 1167 | | -** and/or name going from pid to cid. |
| 1181 | +** A single mlink entry is added for every file that changed content, |
| 1182 | +** name, and/or permissions going from pid to cid. |
| 1168 | 1183 | ** |
| 1169 | 1184 | ** Deleted files have mlink.fid=0. |
| 1170 | 1185 | ** Added files have mlink.pid=0. |
| 1171 | 1186 | ** Edited files have both mlink.pid!=0 and mlink.fid!=0 |
| 1172 | 1187 | */ |
| | @@ -1176,16 +1191,22 @@ |
| 1176 | 1191 | int i, rc; |
| 1177 | 1192 | ManifestFile *pChildFile, *pParentFile; |
| 1178 | 1193 | Manifest **ppOther; |
| 1179 | 1194 | static Stmt eq; |
| 1180 | 1195 | |
| 1196 | + /* If mlink table entires are already set for cid, then abort early |
| 1197 | + ** doing no work. |
| 1198 | + */ |
| 1181 | 1199 | db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid"); |
| 1182 | 1200 | db_bind_int(&eq, ":mid", cid); |
| 1183 | 1201 | rc = db_step(&eq); |
| 1184 | 1202 | db_reset(&eq); |
| 1185 | 1203 | if( rc==SQLITE_ROW ) return; |
| 1186 | 1204 | |
| 1205 | + /* Compute the value of the missing pParent or pChild parameter. |
| 1206 | + ** Fetch the baseline checkins for both. |
| 1207 | + */ |
| 1187 | 1208 | assert( pParent==0 || pChild==0 ); |
| 1188 | 1209 | if( pParent==0 ){ |
| 1189 | 1210 | ppOther = &pParent; |
| 1190 | 1211 | otherRid = pid; |
| 1191 | 1212 | }else{ |
| | @@ -1200,10 +1221,14 @@ |
| 1200 | 1221 | } |
| 1201 | 1222 | if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){ |
| 1202 | 1223 | manifest_destroy(*ppOther); |
| 1203 | 1224 | return; |
| 1204 | 1225 | } |
| 1226 | + |
| 1227 | + /* Try to make the parent manifest a delta from the child, if that |
| 1228 | + ** is an appropriate thing to do. |
| 1229 | + */ |
| 1205 | 1230 | if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){ |
| 1206 | 1231 | content_deltify(pid, cid, 0); |
| 1207 | 1232 | }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){ |
| 1208 | 1233 | content_deltify(pParent->pBaseline->rid, cid, 0); |
| 1209 | 1234 | } |
| | @@ -1217,44 +1242,63 @@ |
| 1217 | 1242 | db_multi_exec( |
| 1218 | 1243 | "INSERT OR REPLACE INTO time_fudge VALUES(%d, %.17g, %d, %.17g);", |
| 1219 | 1244 | pParent->rid, pParent->rDate, pChild->rid, pChild->rDate |
| 1220 | 1245 | ); |
| 1221 | 1246 | } |
| 1222 | | - |
| 1247 | + |
| 1248 | + /* First look at all files in pChild, ignoring its baseline. This |
| 1249 | + ** is where most of the changes will be found. |
| 1250 | + */ |
| 1223 | 1251 | for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){ |
| 1252 | + int mperm = manifest_file_mperm(pChildFile); |
| 1224 | 1253 | if( pChildFile->zPrior ){ |
| 1225 | 1254 | pParentFile = manifest_file_seek(pParent, pChildFile->zPrior); |
| 1226 | 1255 | if( pParentFile ){ |
| 1256 | + /* File with name change */ |
| 1227 | 1257 | add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid, |
| 1228 | | - pChildFile->zName, pChildFile->zPrior); |
| 1258 | + pChildFile->zName, pChildFile->zPrior, mperm); |
| 1259 | + }else{ |
| 1260 | + /* File name changed, but the old name is not found in the parent! |
| 1261 | + ** Treat this like a new file. */ |
| 1262 | + add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0, mperm); |
| 1229 | 1263 | } |
| 1230 | 1264 | }else{ |
| 1231 | 1265 | pParentFile = manifest_file_seek(pParent, pChildFile->zName); |
| 1232 | 1266 | if( pParentFile==0 ){ |
| 1233 | 1267 | if( pChildFile->zUuid ){ |
| 1234 | | - add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0); |
| 1268 | + /* A new file */ |
| 1269 | + add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName,0,mperm); |
| 1235 | 1270 | } |
| 1236 | | - }else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0 ){ |
| 1271 | + }else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0 |
| 1272 | + || manifest_file_mperm(pParentFile)!=mperm ){ |
| 1273 | + /* Changes in file content or permissions */ |
| 1237 | 1274 | add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid, |
| 1238 | | - pChildFile->zName, 0); |
| 1275 | + pChildFile->zName, 0, mperm); |
| 1239 | 1276 | } |
| 1240 | 1277 | } |
| 1241 | 1278 | } |
| 1242 | 1279 | if( pParent->zBaseline && pChild->zBaseline ){ |
| 1280 | + /* Both parent and child are delta manifests. Look for files that |
| 1281 | + ** are marked as deleted in the parent but which reappear in the child |
| 1282 | + ** and show such files as being added in the child. */ |
| 1243 | 1283 | for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){ |
| 1244 | 1284 | if( pParentFile->zUuid ) continue; |
| 1245 | 1285 | pChildFile = manifest_file_seek(pChild, pParentFile->zName); |
| 1246 | 1286 | if( pChildFile ){ |
| 1247 | | - add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0); |
| 1287 | + add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0, |
| 1288 | + manifest_file_mperm(pChildFile)); |
| 1248 | 1289 | } |
| 1249 | 1290 | } |
| 1250 | 1291 | }else if( pChild->zBaseline==0 ){ |
| 1292 | + /* Parent is a delta but pChild is a baseline. Look for files that are |
| 1293 | + ** present in pParent but which are missing from pChild and mark them |
| 1294 | + ** has having been deleted. */ |
| 1251 | 1295 | manifest_file_rewind(pParent); |
| 1252 | 1296 | while( (pParentFile = manifest_file_next(pParent,0))!=0 ){ |
| 1253 | 1297 | pChildFile = manifest_file_seek(pChild, pParentFile->zName); |
| 1254 | 1298 | if( pChildFile==0 ){ |
| 1255 | | - add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0); |
| 1299 | + add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0, 0); |
| 1256 | 1300 | } |
| 1257 | 1301 | } |
| 1258 | 1302 | } |
| 1259 | 1303 | manifest_cache_insert(*ppOther); |
| 1260 | 1304 | } |
| | @@ -1483,12 +1527,15 @@ |
| 1483 | 1527 | int cid = db_column_int(&q, 0); |
| 1484 | 1528 | add_mlink(rid, p, cid, 0); |
| 1485 | 1529 | } |
| 1486 | 1530 | db_finalize(&q); |
| 1487 | 1531 | if( p->nParent==0 ){ |
| 1532 | + /* For root files (files without parents) add mlink entries |
| 1533 | + ** showing all content as new. */ |
| 1488 | 1534 | for(i=0; i<p->nFile; i++){ |
| 1489 | | - add_one_mlink(rid, 0, p->aFile[i].zUuid, p->aFile[i].zName, 0); |
| 1535 | + add_one_mlink(rid, 0, p->aFile[i].zUuid, p->aFile[i].zName, 0, |
| 1536 | + manifest_file_mperm(&p->aFile[i])); |
| 1490 | 1537 | } |
| 1491 | 1538 | } |
| 1492 | 1539 | db_multi_exec( |
| 1493 | 1540 | "REPLACE INTO event(type,mtime,objid,user,comment," |
| 1494 | 1541 | "bgcolor,euser,ecomment,omtime)" |
| 1495 | 1542 | |