/ Check-in [f69e8194]
Login

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

Overview
Comment:Rearrange things a bit so that writing to a zipfile does not invert the order of objects it contains.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sqlar-shell-support
Files: files | file ages | folders
SHA3-256:f69e8194bfa7de436c96028730ebd57f186d2e6207792e172e1aa38c7f4211c9
User & Date: dan 2017-12-30 14:26:29
Context
2017-12-30
18:32
Have zipfile support DELETE commands. check-in: 01d4e866 user: dan tags: sqlar-shell-support
14:26
Rearrange things a bit so that writing to a zipfile does not invert the order of objects it contains. check-in: f69e8194 user: dan tags: sqlar-shell-support
2017-12-29
20:19
Update ext/misc/zipfile.c to support creating and adding entries to existing zip archives. check-in: 2dec2dec user: dan tags: sqlar-shell-support
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/misc/zipfile.c.

   214    214     int bEof;                  /* True when at EOF */
   215    215     i64 iNextOff;              /* Offset of next record in central directory */
   216    216     ZipfileEOCD eocd;          /* Parse of central directory record */
   217    217     ZipfileCDS cds;            /* Central Directory Structure */
   218    218     ZipfileLFH lfh;            /* Local File Header for current entry */
   219    219     i64 iDataOff;              /* Offset in zipfile to data */
   220    220     u32 mTime;                 /* Extended mtime value */
   221         -  int flags;
          221  +  int flags;                 /* Flags byte (see below for bits) */
   222    222   };
   223    223   
   224    224   /*
   225    225   ** Values for ZipfileCsr.flags.
   226    226   */
   227    227   #define ZIPFILE_MTIME_VALID 0x0001
   228    228   
   229    229   typedef struct ZipfileEntry ZipfileEntry;
   230    230   struct ZipfileEntry {
   231    231     char *zPath;               /* Path of zipfile entry */
          232  +  i64 iRowid;                /* Rowid for this value if queried */
   232    233     u8 *aCdsEntry;             /* Buffer containing entire CDS entry */
   233    234     int nCdsEntry;             /* Size of buffer aCdsEntry[] in bytes */
   234         -  ZipfileEntry *pNext;
          235  +  ZipfileEntry *pNext;       /* Next element in in-memory CDS */
   235    236   };
   236    237   
   237    238   typedef struct ZipfileTab ZipfileTab;
   238    239   struct ZipfileTab {
   239    240     sqlite3_vtab base;         /* Base class - must be first */
   240    241     char *zFile;               /* Zip file this table accesses (may be NULL) */
   241    242     u8 *aBuffer;               /* Temporary buffer used for various tasks */
   242    243   
   243    244     /* The following are used by write transactions only */
   244         -  ZipfileEntry *pEntry;      /* Linked list of all files (if pWriteFd!=0) */
          245  +  ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */
          246  +  ZipfileEntry *pLastEntry;  /* Last element in pFirstEntry list */
   245    247     FILE *pWriteFd;            /* File handle open on zip archive */
   246    248     i64 szCurrent;             /* Current size of zip archive */
   247    249     i64 szOrig;                /* Size of archive at start of transaction */
   248    250   };
   249    251   
   250    252   static void zipfileDequote(char *zIn){
   251    253     char q = zIn[0];
................................................................................
   825    827     }else{
   826    828       pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
   827    829       pIdxInfo->idxNum = 0;
   828    830     }
   829    831   
   830    832     return SQLITE_OK;
   831    833   }
          834  +
          835  +/*
          836  +** Add object pNew to the end of the linked list that begins at
          837  +** ZipfileTab.pFirstEntry and ends with pLastEntry.
          838  +*/
          839  +static void zipfileAddEntry(ZipfileTab *pTab, ZipfileEntry *pNew){
          840  +  assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
          841  +  assert( pNew->pNext==0 );
          842  +  if( pTab->pFirstEntry==0 ){
          843  +    pTab->pFirstEntry = pTab->pLastEntry = pNew;
          844  +  }else{
          845  +    assert( pTab->pLastEntry->pNext==0 );
          846  +    pTab->pLastEntry->pNext = pNew;
          847  +    pTab->pLastEntry = pNew;
          848  +  }
          849  +}
   832    850   
   833    851   static int zipfileLoadDirectory(ZipfileTab *pTab){
   834    852     ZipfileEOCD eocd;
   835    853     int rc;
   836    854   
   837    855     rc = zipfileReadEOCD(pTab, pTab->pWriteFd, &eocd);
   838    856     if( rc==SQLITE_OK ){
................................................................................
   867    885           rc = SQLITE_NOMEM;
   868    886         }else{
   869    887           pNew->zPath = (char*)&pNew[1];
   870    888           memcpy(pNew->zPath, &aBuf[ZIPFILE_CDS_FIXED_SZ], nFile);
   871    889           pNew->zPath[nFile] = '\0';
   872    890           pNew->aCdsEntry = (u8*)&pNew->zPath[nFile+1];
   873    891           pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
          892  +        pNew->pNext = 0;
   874    893           memcpy(pNew->aCdsEntry, aRec, pNew->nCdsEntry);
   875         -
   876         -        pNew->pNext = pTab->pEntry;
   877         -        pTab->pEntry = pNew;
          894  +        zipfileAddEntry(pTab, pNew);
   878    895         }
   879    896   
   880    897         iOff += ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
   881    898       }
   882    899   
   883    900       sqlite3_free(aBuf);
   884    901     }else if( rc==SQLITE_EMPTY ){
................................................................................
   904    921       ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra
   905    922     );
   906    923   
   907    924     if( pNew ){
   908    925       pNew->zPath = (char*)&pNew[1];
   909    926       pNew->aCdsEntry = (u8*)&pNew->zPath[nPath+1];
   910    927       pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra;
          928  +    pNew->pNext = 0;
   911    929       memcpy(pNew->zPath, zPath, nPath+1);
   912    930   
   913    931       aWrite = pNew->aCdsEntry;
   914    932       zipfileWrite32(aWrite, ZIPFILE_SIGNATURE_CDS);
   915    933       zipfileWrite16(aWrite, pCds->iVersionMadeBy);
   916    934       zipfileWrite16(aWrite, pCds->iVersionExtract);
   917    935       zipfileWrite16(aWrite, pCds->flags);
................................................................................
  1131   1149       cds.szUncompressed = sz;
  1132   1150       cds.iExternalAttr = (mode<<16);
  1133   1151       cds.iOffset = pTab->szCurrent;
  1134   1152       pNew = zipfileNewEntry(&cds, zPath, nPath, (u32)mTime);
  1135   1153       if( pNew==0 ){
  1136   1154         rc = SQLITE_NOMEM;
  1137   1155       }else{
  1138         -      pNew->pNext = pTab->pEntry;
  1139         -      pTab->pEntry = pNew;
         1156  +      zipfileAddEntry(pTab, pNew);
  1140   1157       }
  1141   1158     }
  1142   1159   
  1143   1160     /* Append the new header+file to the archive */
  1144   1161     if( rc==SQLITE_OK ){
  1145   1162       rc = zipfileAppendEntry(pTab, &cds, zPath, nPath, pData, nData, (u32)mTime);
  1146   1163     }
................................................................................
  1165   1182     return zipfileAppendData(pTab, pTab->aBuffer, aBuf - pTab->aBuffer);
  1166   1183   }
  1167   1184   
  1168   1185   static void zipfileCleanupTransaction(ZipfileTab *pTab){
  1169   1186     ZipfileEntry *pEntry;
  1170   1187     ZipfileEntry *pNext;
  1171   1188   
  1172         -  for(pEntry=pTab->pEntry; pEntry; pEntry=pNext){
         1189  +  for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){
  1173   1190       pNext = pEntry->pNext;
  1174   1191       sqlite3_free(pEntry);
  1175   1192     }
  1176         -  pTab->pEntry = 0;
         1193  +  pTab->pFirstEntry = 0;
         1194  +  pTab->pLastEntry = 0;
  1177   1195     fclose(pTab->pWriteFd);
  1178   1196     pTab->pWriteFd = 0;
  1179   1197     pTab->szCurrent = 0;
  1180   1198     pTab->szOrig = 0;
  1181   1199   }
  1182   1200   
  1183   1201   static int zipfileBegin(sqlite3_vtab *pVtab){
................................................................................
  1185   1203   }
  1186   1204   
  1187   1205   static int zipfileCommit(sqlite3_vtab *pVtab){
  1188   1206     ZipfileTab *pTab = (ZipfileTab*)pVtab;
  1189   1207     int rc = SQLITE_OK;
  1190   1208     if( pTab->pWriteFd ){
  1191   1209       i64 iOffset = pTab->szCurrent;
  1192         -    ZipfileEntry *pEntry;
         1210  +    ZipfileEntry *p;
  1193   1211       ZipfileEOCD eocd;
  1194   1212       int nEntry = 0;
  1195   1213   
  1196   1214       /* Write out all entries */
  1197         -    for(pEntry=pTab->pEntry; rc==SQLITE_OK && pEntry; pEntry=pEntry->pNext){
  1198         -      rc = zipfileAppendData(pTab, pEntry->aCdsEntry, pEntry->nCdsEntry);
         1215  +    for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){
         1216  +      rc = zipfileAppendData(pTab, p->aCdsEntry, p->nCdsEntry);
  1199   1217         nEntry++;
  1200   1218       }
  1201   1219   
  1202   1220       /* Write out the EOCD record */
  1203   1221       eocd.iDisk = 0;
  1204   1222       eocd.iFirstDisk = 0;
  1205   1223       eocd.nEntry = nEntry;

Changes to test/zipfile.test.

    33     33     INSERT INTO zz VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
    34     34     INSERT INTO zz VALUES('g.txt', '-rw-r--r--', 1000000002, 5, '12345', 0);
    35     35   }
    36     36   
    37     37   do_execsql_test 1.2 {
    38     38     SELECT name, mtime, data FROM zipfile('test.zip');
    39     39   } {
    40         -  g.txt 1000000002 12345
    41     40     f.txt 1000000000 abcde 
           41  +  g.txt 1000000002 12345
    42     42   }
    43     43   
    44     44   do_execsql_test 1.3 {
    45     45     INSERT INTO zz VALUES('h.txt', 
    46     46       '-rw-r--r--', 1000000004, 20, 'aaaaaaaaaabbbbbbbbbb', NULL
    47     47     );
    48     48   }
    49     49   
    50     50   do_execsql_test 1.4 {
    51     51     SELECT name, mtime, zipfile_uncompress(data, sz, method), method
    52     52     FROM zipfile('test.zip');
    53     53   } {
    54         -  h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
    55     54     f.txt 1000000000 abcde 0
    56     55     g.txt 1000000002 12345 0
           56  +  h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
    57     57   }
    58     58   
    59     59   finish_test
    60     60