Fossil SCM
Handle short UUID collisions for events, tickets and other artifacts in the /info page.
Commit
49467d2a494aae8b65e6ec8d118cb4fb0fe080c1
Parent
61c66596e88f252…
2 files changed
+21
-10
+68
-1
+21
-10
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1890,28 +1890,39 @@ | ||
| 1890 | 1890 | void info_page(void){ |
| 1891 | 1891 | const char *zName; |
| 1892 | 1892 | Blob uuid; |
| 1893 | 1893 | int rid; |
| 1894 | 1894 | int rc; |
| 1895 | + int nLen; | |
| 1895 | 1896 | |
| 1896 | 1897 | zName = P("name"); |
| 1897 | 1898 | if( zName==0 ) fossil_redirect_home(); |
| 1898 | - if( validate16(zName, strlen(zName)) ){ | |
| 1899 | - if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ | |
| 1900 | - tktview_page(); | |
| 1901 | - return; | |
| 1902 | - } | |
| 1903 | - if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){ | |
| 1904 | - event_page(); | |
| 1905 | - return; | |
| 1906 | - } | |
| 1907 | - } | |
| 1899 | + nLen = strlen(zName); | |
| 1908 | 1900 | blob_set(&uuid, zName); |
| 1901 | + if( name_collisions(zName) ){ | |
| 1902 | + cgi_set_parameter("src","info"); | |
| 1903 | + ambiguous_page(); | |
| 1904 | + return; | |
| 1905 | + } | |
| 1909 | 1906 | rc = name_to_uuid(&uuid, -1, "*"); |
| 1910 | 1907 | if( rc==1 ){ |
| 1908 | + if( validate16(zName, nLen) ){ | |
| 1909 | + if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ | |
| 1910 | + tktview_page(); | |
| 1911 | + return; | |
| 1912 | + } | |
| 1913 | + if( db_exists("SELECT 1 FROM tag" | |
| 1914 | + " WHERE tagname GLOB 'event-%q*'", zName) ){ | |
| 1915 | + event_page(); | |
| 1916 | + return; | |
| 1917 | + } | |
| 1918 | + } | |
| 1911 | 1919 | style_header("No Such Object"); |
| 1912 | 1920 | @ <p>No such object: %h(zName)</p> |
| 1921 | + if( nLen<4 ){ | |
| 1922 | + @ <p>Objects of length < 4 are too ambiguous to worry about</p> | |
| 1923 | + } | |
| 1913 | 1924 | style_footer(); |
| 1914 | 1925 | return; |
| 1915 | 1926 | }else if( rc==2 ){ |
| 1916 | 1927 | cgi_set_parameter("src","info"); |
| 1917 | 1928 | ambiguous_page(); |
| 1918 | 1929 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1890,28 +1890,39 @@ | |
| 1890 | void info_page(void){ |
| 1891 | const char *zName; |
| 1892 | Blob uuid; |
| 1893 | int rid; |
| 1894 | int rc; |
| 1895 | |
| 1896 | zName = P("name"); |
| 1897 | if( zName==0 ) fossil_redirect_home(); |
| 1898 | if( validate16(zName, strlen(zName)) ){ |
| 1899 | if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ |
| 1900 | tktview_page(); |
| 1901 | return; |
| 1902 | } |
| 1903 | if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){ |
| 1904 | event_page(); |
| 1905 | return; |
| 1906 | } |
| 1907 | } |
| 1908 | blob_set(&uuid, zName); |
| 1909 | rc = name_to_uuid(&uuid, -1, "*"); |
| 1910 | if( rc==1 ){ |
| 1911 | style_header("No Such Object"); |
| 1912 | @ <p>No such object: %h(zName)</p> |
| 1913 | style_footer(); |
| 1914 | return; |
| 1915 | }else if( rc==2 ){ |
| 1916 | cgi_set_parameter("src","info"); |
| 1917 | ambiguous_page(); |
| 1918 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1890,28 +1890,39 @@ | |
| 1890 | void info_page(void){ |
| 1891 | const char *zName; |
| 1892 | Blob uuid; |
| 1893 | int rid; |
| 1894 | int rc; |
| 1895 | int nLen; |
| 1896 | |
| 1897 | zName = P("name"); |
| 1898 | if( zName==0 ) fossil_redirect_home(); |
| 1899 | nLen = strlen(zName); |
| 1900 | blob_set(&uuid, zName); |
| 1901 | if( name_collisions(zName) ){ |
| 1902 | cgi_set_parameter("src","info"); |
| 1903 | ambiguous_page(); |
| 1904 | return; |
| 1905 | } |
| 1906 | rc = name_to_uuid(&uuid, -1, "*"); |
| 1907 | if( rc==1 ){ |
| 1908 | if( validate16(zName, nLen) ){ |
| 1909 | if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ |
| 1910 | tktview_page(); |
| 1911 | return; |
| 1912 | } |
| 1913 | if( db_exists("SELECT 1 FROM tag" |
| 1914 | " WHERE tagname GLOB 'event-%q*'", zName) ){ |
| 1915 | event_page(); |
| 1916 | return; |
| 1917 | } |
| 1918 | } |
| 1919 | style_header("No Such Object"); |
| 1920 | @ <p>No such object: %h(zName)</p> |
| 1921 | if( nLen<4 ){ |
| 1922 | @ <p>Objects of length < 4 are too ambiguous to worry about</p> |
| 1923 | } |
| 1924 | style_footer(); |
| 1925 | return; |
| 1926 | }else if( rc==2 ){ |
| 1927 | cgi_set_parameter("src","info"); |
| 1928 | ambiguous_page(); |
| 1929 |
+68
-1
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -266,11 +266,10 @@ | ||
| 266 | 266 | } |
| 267 | 267 | } |
| 268 | 268 | return rid; |
| 269 | 269 | } |
| 270 | 270 | |
| 271 | - | |
| 272 | 271 | /* |
| 273 | 272 | ** This routine takes a user-entered UUID which might be in mixed |
| 274 | 273 | ** case and might only be a prefix of the full UUID and converts it |
| 275 | 274 | ** into the full-length UUID in canonical form. |
| 276 | 275 | ** |
| @@ -319,10 +318,39 @@ | ||
| 319 | 318 | } |
| 320 | 319 | return rid; |
| 321 | 320 | } |
| 322 | 321 | |
| 323 | 322 | |
| 323 | +/* | |
| 324 | +** name_collisions searches through events, blobs, and tickets for | |
| 325 | +** collisions of a given UUID based on its length on UUIDs no shorter | |
| 326 | +** than 4 characters in length. | |
| 327 | +*/ | |
| 328 | +int name_collisions(const char *zName){ | |
| 329 | + Stmt q; | |
| 330 | + int c = 0; /* count of collisions for zName */ | |
| 331 | + int nLen; /* length of zName */ | |
| 332 | + nLen = strlen(zName); | |
| 333 | + if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){ | |
| 334 | + db_prepare(&q, | |
| 335 | + "SELECT count(uuid) FROM" | |
| 336 | + " (SELECT substr(tkt_uuid, 1, %d) AS uuid FROM ticket" | |
| 337 | + " UNION ALL SELECT * FROM" | |
| 338 | + " (SELECT substr(tagname, 7, %d) FROM" | |
| 339 | + " tag WHERE tagname GLOB 'event-*')" | |
| 340 | + " UNION ALL SELECT * FROM" | |
| 341 | + " (SELECT substr(uuid, 1, %d) FROM blob))" | |
| 342 | + " WHERE uuid GLOB '%q*'" | |
| 343 | + " GROUP BY uuid HAVING count(uuid) > 1;", | |
| 344 | + nLen, nLen, nLen, zName); | |
| 345 | + if( db_step(&q)==SQLITE_ROW ){ | |
| 346 | + c = db_column_int(&q, 0); | |
| 347 | + } | |
| 348 | + db_finalize(&q); | |
| 349 | + } | |
| 350 | + return c; | |
| 351 | +} | |
| 324 | 352 | |
| 325 | 353 | /* |
| 326 | 354 | ** COMMAND: test-name-to-id |
| 327 | 355 | ** |
| 328 | 356 | ** Convert a name to a full artifact ID. |
| @@ -406,10 +434,49 @@ | ||
| 406 | 434 | int rid = db_column_int(&q, 1); |
| 407 | 435 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 408 | 436 | @ %s(zUuid)</a> - |
| 409 | 437 | object_description(rid, 0, 0); |
| 410 | 438 | @ </p></li> |
| 439 | + } | |
| 440 | + db_finalize(&q); | |
| 441 | + db_prepare(&q, | |
| 442 | + " SELECT tkt_rid, tkt_uuid, title" | |
| 443 | + " FROM ticket, ticketchng" | |
| 444 | + " WHERE ticket.tkt_id = ticketchng.tkt_id" | |
| 445 | + " AND tkt_uuid GLOB '%q*'" | |
| 446 | + " GROUP BY tkt_uuid" | |
| 447 | + " ORDER BY tkt_ctime DESC", z); | |
| 448 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 449 | + int rid = db_column_int(&q, 0); | |
| 450 | + const char *zUuid = db_column_text(&q, 1); | |
| 451 | + const char *zTitle = db_column_text(&q, 2); | |
| 452 | + @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> | |
| 453 | + @ %s(zUuid)</a> - | |
| 454 | + @ <ul></ul> | |
| 455 | + @ Ticket | |
| 456 | + hyperlink_to_uuid(zUuid); | |
| 457 | + @ - %s(zTitle). | |
| 458 | + @ <ul><li> | |
| 459 | + object_description(rid, 0, 0); | |
| 460 | + @ </li></ul> | |
| 461 | + @ </p></li> | |
| 462 | + } | |
| 463 | + db_finalize(&q); | |
| 464 | + db_prepare(&q, | |
| 465 | + "SELECT rid, uuid FROM" | |
| 466 | + " (SELECT tagxref.rid AS rid, substr(tagname, 7) AS uuid" | |
| 467 | + " FROM tagxref, tag WHERE tagxref.tagid = tag.tagid" | |
| 468 | + " AND tagname GLOB 'event-%q*') GROUP BY uuid", z); | |
| 469 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 470 | + int rid = db_column_int(&q, 0); | |
| 471 | + const char* zUuid = db_column_text(&q, 1); | |
| 472 | + @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> | |
| 473 | + @ %s(zUuid)</a> - | |
| 474 | + @ <ul><li> | |
| 475 | + object_description(rid, 0, 0); | |
| 476 | + @ </li></ul> | |
| 477 | + @ </p></li> | |
| 411 | 478 | } |
| 412 | 479 | @ </ol> |
| 413 | 480 | db_finalize(&q); |
| 414 | 481 | style_footer(); |
| 415 | 482 | } |
| 416 | 483 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -266,11 +266,10 @@ | |
| 266 | } |
| 267 | } |
| 268 | return rid; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | /* |
| 273 | ** This routine takes a user-entered UUID which might be in mixed |
| 274 | ** case and might only be a prefix of the full UUID and converts it |
| 275 | ** into the full-length UUID in canonical form. |
| 276 | ** |
| @@ -319,10 +318,39 @@ | |
| 319 | } |
| 320 | return rid; |
| 321 | } |
| 322 | |
| 323 | |
| 324 | |
| 325 | /* |
| 326 | ** COMMAND: test-name-to-id |
| 327 | ** |
| 328 | ** Convert a name to a full artifact ID. |
| @@ -406,10 +434,49 @@ | |
| 406 | int rid = db_column_int(&q, 1); |
| 407 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 408 | @ %s(zUuid)</a> - |
| 409 | object_description(rid, 0, 0); |
| 410 | @ </p></li> |
| 411 | } |
| 412 | @ </ol> |
| 413 | db_finalize(&q); |
| 414 | style_footer(); |
| 415 | } |
| 416 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -266,11 +266,10 @@ | |
| 266 | } |
| 267 | } |
| 268 | return rid; |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | ** This routine takes a user-entered UUID which might be in mixed |
| 273 | ** case and might only be a prefix of the full UUID and converts it |
| 274 | ** into the full-length UUID in canonical form. |
| 275 | ** |
| @@ -319,10 +318,39 @@ | |
| 318 | } |
| 319 | return rid; |
| 320 | } |
| 321 | |
| 322 | |
| 323 | /* |
| 324 | ** name_collisions searches through events, blobs, and tickets for |
| 325 | ** collisions of a given UUID based on its length on UUIDs no shorter |
| 326 | ** than 4 characters in length. |
| 327 | */ |
| 328 | int name_collisions(const char *zName){ |
| 329 | Stmt q; |
| 330 | int c = 0; /* count of collisions for zName */ |
| 331 | int nLen; /* length of zName */ |
| 332 | nLen = strlen(zName); |
| 333 | if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){ |
| 334 | db_prepare(&q, |
| 335 | "SELECT count(uuid) FROM" |
| 336 | " (SELECT substr(tkt_uuid, 1, %d) AS uuid FROM ticket" |
| 337 | " UNION ALL SELECT * FROM" |
| 338 | " (SELECT substr(tagname, 7, %d) FROM" |
| 339 | " tag WHERE tagname GLOB 'event-*')" |
| 340 | " UNION ALL SELECT * FROM" |
| 341 | " (SELECT substr(uuid, 1, %d) FROM blob))" |
| 342 | " WHERE uuid GLOB '%q*'" |
| 343 | " GROUP BY uuid HAVING count(uuid) > 1;", |
| 344 | nLen, nLen, nLen, zName); |
| 345 | if( db_step(&q)==SQLITE_ROW ){ |
| 346 | c = db_column_int(&q, 0); |
| 347 | } |
| 348 | db_finalize(&q); |
| 349 | } |
| 350 | return c; |
| 351 | } |
| 352 | |
| 353 | /* |
| 354 | ** COMMAND: test-name-to-id |
| 355 | ** |
| 356 | ** Convert a name to a full artifact ID. |
| @@ -406,10 +434,49 @@ | |
| 434 | int rid = db_column_int(&q, 1); |
| 435 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 436 | @ %s(zUuid)</a> - |
| 437 | object_description(rid, 0, 0); |
| 438 | @ </p></li> |
| 439 | } |
| 440 | db_finalize(&q); |
| 441 | db_prepare(&q, |
| 442 | " SELECT tkt_rid, tkt_uuid, title" |
| 443 | " FROM ticket, ticketchng" |
| 444 | " WHERE ticket.tkt_id = ticketchng.tkt_id" |
| 445 | " AND tkt_uuid GLOB '%q*'" |
| 446 | " GROUP BY tkt_uuid" |
| 447 | " ORDER BY tkt_ctime DESC", z); |
| 448 | while( db_step(&q)==SQLITE_ROW ){ |
| 449 | int rid = db_column_int(&q, 0); |
| 450 | const char *zUuid = db_column_text(&q, 1); |
| 451 | const char *zTitle = db_column_text(&q, 2); |
| 452 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 453 | @ %s(zUuid)</a> - |
| 454 | @ <ul></ul> |
| 455 | @ Ticket |
| 456 | hyperlink_to_uuid(zUuid); |
| 457 | @ - %s(zTitle). |
| 458 | @ <ul><li> |
| 459 | object_description(rid, 0, 0); |
| 460 | @ </li></ul> |
| 461 | @ </p></li> |
| 462 | } |
| 463 | db_finalize(&q); |
| 464 | db_prepare(&q, |
| 465 | "SELECT rid, uuid FROM" |
| 466 | " (SELECT tagxref.rid AS rid, substr(tagname, 7) AS uuid" |
| 467 | " FROM tagxref, tag WHERE tagxref.tagid = tag.tagid" |
| 468 | " AND tagname GLOB 'event-%q*') GROUP BY uuid", z); |
| 469 | while( db_step(&q)==SQLITE_ROW ){ |
| 470 | int rid = db_column_int(&q, 0); |
| 471 | const char* zUuid = db_column_text(&q, 1); |
| 472 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 473 | @ %s(zUuid)</a> - |
| 474 | @ <ul><li> |
| 475 | object_description(rid, 0, 0); |
| 476 | @ </li></ul> |
| 477 | @ </p></li> |
| 478 | } |
| 479 | @ </ol> |
| 480 | db_finalize(&q); |
| 481 | style_footer(); |
| 482 | } |
| 483 |