Fossil

Check-in [983331a13a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add links to tarball and ZIP downloads from /dir and /tree pages. Standardize ZIP and tarball basenames using the archive_base_name() routine.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | timeline-enhance-2025
Files: files | file ages | folders
SHA3-256: 983331a13a9062e23f103246c52f8ce980c6c35df21452cc841ba0b6c2e2835b
User & Date: drh 2025-10-18 01:20:56.539
Context
2025-10-18
01:43
Remove the "tarzip" query parameter from /timeline. Make the default suggested-tarlist be "off" so that the /tarlist pages is disabled by default. check-in: bdbf5db222 user: drh tags: timeline-enhance-2025
01:20
Add links to tarball and ZIP downloads from /dir and /tree pages. Standardize ZIP and tarball basenames using the archive_base_name() routine. check-in: 983331a13a user: drh tags: timeline-enhance-2025
2025-10-17
16:38
Change the title of the /brtimeline page back to the way it was. Add the timelineX restriction to /brtimeline. check-in: 881b705b65 user: drh tags: timeline-enhance-2025
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/browse.c.
227
228
229
230
231
232
233








234
235
236
237
238
239
240
    zHeader = mprintf("%z matching \"%s\"", zHeader, zRegexp);
    zMatch = mprintf(" matching \"%h\"", zRegexp);
  }else{
    zMatch = "";
  }
  style_header("%s", zHeader);
  fossil_free(zHeader);








  style_adunit_config(ADUNIT_RIGHT_OK);
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
  url_initialize(&sURI, "dir");
  cgi_check_for_malice();
  cgi_query_parameters_to_url(&sURI);








>
>
>
>
>
>
>
>







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    zHeader = mprintf("%z matching \"%s\"", zHeader, zRegexp);
    zMatch = mprintf(" matching \"%h\"", zRegexp);
  }else{
    zMatch = "";
  }
  style_header("%s", zHeader);
  fossil_free(zHeader);
  if( rid && zD==0 && zMatch[0]==0 && g.perm.Zip ){
    char *zBase = archive_base_name(rid);
    style_submenu_element("Tarball","%R/tarball/%!S/%s.tar.gz",
                          zUuid, zBase);
    style_submenu_element("ZIP","%R/zip/%!S/%s.zip",
                          zUuid, zBase);
    fossil_free(zBase);
  }
  style_adunit_config(ADUNIT_RIGHT_OK);
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
  url_initialize(&sURI, "dir");
  cgi_check_for_malice();
  cgi_query_parameters_to_url(&sURI);

812
813
814
815
816
817
818








819
820
821
822
823
824
825
  if( zCI ){
    if( nD==0 && !showDirOnly ){
      style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
    }
  }
  style_submenu_element("Flat-View", "%s",
                        url_render(&sURI, "type", "flat", 0, 0));









  /* Compute the file hierarchy.
  */
  if( zCI ){
    Stmt q;
    compute_fileage(rid, 0);
    db_prepare(&q,







>
>
>
>
>
>
>
>







820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  if( zCI ){
    if( nD==0 && !showDirOnly ){
      style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
    }
  }
  style_submenu_element("Flat-View", "%s",
                        url_render(&sURI, "type", "flat", 0, 0));
  if( rid && zD==0 && zRE==0 && !showDirOnly && g.perm.Zip ){
    char *zBase = archive_base_name(rid);
    style_submenu_element("Tarball","%R/tarball/%!S/%s.tar.gz",
                          zUuid, zBase);
    style_submenu_element("ZIP","%R/zip/%!S/%s.zip",
                          zUuid, zBase);
    fossil_free(zBase);
  }

  /* Compute the file hierarchy.
  */
  if( zCI ){
    Stmt q;
    compute_fileage(rid, 0);
    db_prepare(&q,
Changes to src/db.c.
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  }
  db_finalize(&s);
}

/*
** Execute a query.  Return the first column of the first row
** of the result set as a string.  Space to hold the string is
** obtained from malloc().  If the result set is empty, return
** zDefault instead.
*/
char *db_text(const char *zDefault, const char *zSql, ...){
  va_list ap;
  Stmt s;
  char *z;
  va_start(ap, zSql);
  db_vprepare(&s, 0, zSql, ap);







|
|







1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  }
  db_finalize(&s);
}

/*
** Execute a query.  Return the first column of the first row
** of the result set as a string.  Space to hold the string is
** obtained from fossil_strdup() and should be freed using fossil_free().
** If the result set is empty, return a copy of zDefault instead.
*/
char *db_text(const char *zDefault, const char *zSql, ...){
  va_list ap;
  Stmt s;
  char *z;
  va_start(ap, zSql);
  db_vprepare(&s, 0, zSql, ap);
Changes to src/tar.c.
29
30
31
32
33
34
35







































36
37
38
39
40
41
42
  unsigned char *aHdr;      /* Space for building headers */
  char *zSpaces;            /* Spaces for padding */
  char *zPrevDir;           /* Name of directory for previous entry */
  int nPrevDirAlloc;        /* size of zPrevDir */
  Blob pax;                 /* PAX data */
} tball;









































/*
** field lengths of 'ustar' name and prefix fields.
*/
#define USTAR_NAME_LEN    100
#define USTAR_PREFIX_LEN  155








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  unsigned char *aHdr;      /* Space for building headers */
  char *zSpaces;            /* Spaces for padding */
  char *zPrevDir;           /* Name of directory for previous entry */
  int nPrevDirAlloc;        /* size of zPrevDir */
  Blob pax;                 /* PAX data */
} tball;

/*
** Compute a sensible base-name for an archive file (tarball, ZIP, or SQLAR)
** based on the rid of the check-in contained in that file.
**
**      PROJECTNAME-DATETIME-HASHPREFIX
**
** So that the name will be safe to use as a URL or a filename on any system,
** the name is only allowed to contain lower-case ASCII alphabetics,
** digits, '_' and '-'.  Upper-case ASCII is converted to lower-case.  All
** other bytes are mapped into a lower-case alphabetic.
**
** The value returned is obtained from mprintf() or fossil_strdup() and should
** be released by the caller using fossil_free().
*/
char *archive_base_name(int rid){
  char *zName;
  int i;
  char c;
  zName = db_text(0,
    "SELECT coalesce(config.value,'unnamed')||"
          " strftime('-%%Y%%m%%d%%H%%M%%S-',event.mtime)||"
          " substr(blob.uuid,1,10)"
     " FROM blob, event LEFT JOIN config"
    " WHERE blob.rid=%d"
      " AND event.objid=%d"
      " AND config.name='project-name'",
    rid, rid);
  for(i=0; (c = zName[i])!=0; i++){
    if( fossil_isupper(c) ){
      zName[i] = fossil_tolower(c);
    }else if( !fossil_isalnum(c) && c!='_' && c!='-' ){
              /*  123456789 123456789 123456  */
      zName[i] = "abcdefghijklmnopqrstuvwxyz"[(unsigned)c%26];
    }
  }
  return zName;
}



/*
** field lengths of 'ustar' name and prefix fields.
*/
#define USTAR_NAME_LEN    100
#define USTAR_PREFIX_LEN  155

651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  }
  zOut = g.argv[3];
  if( fossil_strcmp("/dev/null",zOut)==0 || fossil_strcmp("",zOut)==0 ){
    zOut = 0;
  }

  if( zName==0 ){
    zName = db_text("default-name",
       "SELECT replace(%Q,' ','_') "
          " || strftime('_%%Y-%%m-%%d_%%H%%M%%S_', event.mtime) "
          " || substr(blob.uuid, 1, 10)"
       "  FROM event, blob"
       " WHERE event.objid=%d"
       "   AND blob.rid=%d",
       db_get("project-name", "unnamed"), rid, rid
    );
  }
  tarball_of_checkin(rid, zOut ? &tarball : 0,
                     zName, pInclude, pExclude, listFlag);
  glob_free(pInclude);
  glob_free(pExclude);
  if( listFlag ) fflush(stdout);
  if( zOut ){







|
<
<
<
<
<
<
<
<







690
691
692
693
694
695
696
697








698
699
700
701
702
703
704
  }
  zOut = g.argv[3];
  if( fossil_strcmp("/dev/null",zOut)==0 || fossil_strcmp("",zOut)==0 ){
    zOut = 0;
  }

  if( zName==0 ){
    zName = archive_base_name(rid);








  }
  tarball_of_checkin(rid, zOut ? &tarball : 0,
                     zName, pInclude, pExclude, listFlag);
  glob_free(pInclude);
  glob_free(pExclude);
  if( listFlag ) fflush(stdout);
  if( zOut ){
Changes to src/zip.c.
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
  }
  zOut = g.argv[3];
  if( fossil_strcmp(zOut,"")==0 || fossil_strcmp(zOut,"/dev/null")==0 ){
    zOut = 0;
  }

  if( zName==0 ){
    zName = db_text("default-name",
       "SELECT replace(%Q,' ','_') "
          " || strftime('_%%Y-%%m-%%d_%%H%%M%%S_', event.mtime) "
          " || substr(blob.uuid, 1, 10)"
       "  FROM event, blob"
       " WHERE event.objid=%d"
       "   AND blob.rid=%d",
       db_get("project-name", "unnamed"), rid, rid
    );
  }
  zip_of_checkin(eType, rid, zOut ? &zip : 0,
                 zName, pInclude, pExclude, listFlag);
  glob_free(pInclude);
  glob_free(pExclude);
  if( zOut ){
    blob_write_to_file(&zip, zOut);







|
<
<
<
<
<
<
<
<







862
863
864
865
866
867
868
869








870
871
872
873
874
875
876
  }
  zOut = g.argv[3];
  if( fossil_strcmp(zOut,"")==0 || fossil_strcmp(zOut,"/dev/null")==0 ){
    zOut = 0;
  }

  if( zName==0 ){
    zName = archive_base_name(rid);








  }
  zip_of_checkin(eType, rid, zOut ? &zip : 0,
                 zName, pInclude, pExclude, listFlag);
  glob_free(pInclude);
  glob_free(pExclude);
  if( zOut ){
    blob_write_to_file(&zip, zOut);