/ Check-in [f634a7e3]
Login

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

Overview
Comment:Improved error messages from the zipfile extension.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:f634a7e386918b829389f20c330d312315fdd61125cd2c5f66cf17a5d74bce49
User & Date: drh 2018-03-10 13:21:41
Context
2018-03-10
14:17
Add support for INSERT OR REPLACE and INSERT OR IGNORE on the zipfile extension. check-in: 8ad35d48 user: drh tags: trunk
13:21
Improved error messages from the zipfile extension. check-in: f634a7e3 user: drh tags: trunk
12:53
Avoid harmless left-shifts of negative numbers in the zipfile extension when building ZIP archives of files with pre-DOS dates. check-in: 16bba865 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/misc/zipfile.c.

469
470
471
472
473
474
475







476
477
478

479
480
481
482
483
484
485
....
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
....
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
....
1401
1402
1403
1404
1405
1406
1407

1408
1409
1410
1411
1412
1413
1414
....
1531
1532
1533
1534
1535
1536
1537
1538



1539
1540

1541
1542
1543
1544
1545
1546
1547
....
1553
1554
1555
1556
1557
1558
1559

1560
1561
1562
1563
1564
1565
1566
....
1599
1600
1601
1602
1603
1604
1605

1606
1607
1608
1609
1610
1611
1612
  return SQLITE_OK;
}

/*
** Set the error message for the virtual table associated with cursor
** pCsr to the results of vprintf(zFmt, ...).
*/







static void zipfileSetErrmsg(ZipfileCsr *pCsr, const char *zFmt, ...){
  va_list ap;
  va_start(ap, zFmt);

  pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
  va_end(ap);
}

/*
** Read nRead bytes of data from offset iOff of file pFile into buffer
** aRead[]. Return SQLITE_OK if successful, or an SQLite error code
................................................................................
  int bInMemory = 0;              /* True for an in-memory zipfile */

  zipfileResetCursor(pCsr);

  if( pTab->zFile ){
    zFile = pTab->zFile;
  }else if( idxNum==0 ){
    zipfileSetErrmsg(pCsr, "zipfile() function requires an argument");
    return SQLITE_ERROR;
  }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
    const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
    int nBlob = sqlite3_value_bytes(argv[0]);
    assert( pTab->pFirstEntry==0 );
    rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
    pCsr->pFreeEntry = pTab->pFirstEntry;
................................................................................
  }else{
    zFile = (const char*)sqlite3_value_text(argv[0]);
  }

  if( 0==pTab->pWriteFd && 0==bInMemory ){
    pCsr->pFile = fopen(zFile, "rb");
    if( pCsr->pFile==0 ){
      zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile);
      rc = SQLITE_ERROR;
    }else{
      rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
      if( rc==SQLITE_OK ){
        if( pCsr->eocd.nEntry==0 ){
          pCsr->bEof = 1;
        }else{
................................................................................
      if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
      else if( z[i]!='-' ) goto parse_error;
    }
  }
  if( ((mode & S_IFDIR)==0)==bIsDir ){
    /* The "mode" attribute is a directory, but data has been specified.
    ** Or vice-versa - no data but "mode" is a file or symlink.  */

    return SQLITE_CONSTRAINT;
  }
  *pMode = mode;
  return SQLITE_OK;

 parse_error:
  *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
................................................................................
      }
      assert( pOld->pNext );
    }
  }

  if( nVal>1 ){
    /* Check that "sz" and "rawdata" are both NULL: */
    if( sqlite3_value_type(apVal[5])!=SQLITE_NULL



     || sqlite3_value_type(apVal[6])!=SQLITE_NULL
    ){

      rc = SQLITE_CONSTRAINT;
    }

    if( rc==SQLITE_OK ){
      if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
        /* data=NULL. A directory */
        bIsDir = 1;
................................................................................
        int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;

        iMethod = sqlite3_value_int(apVal[8]);
        sz = nIn;
        pData = aIn;
        nData = nIn;
        if( iMethod!=0 && iMethod!=8 ){

          rc = SQLITE_CONSTRAINT;
        }else{
          if( bAuto || iMethod ){
            int nCmp;
            rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg);
            if( rc==SQLITE_OK ){
              if( iMethod || nCmp<nIn ){
................................................................................
    }

    /* Check that we're not inserting a duplicate entry */
    if( pOld==0 && rc==SQLITE_OK ){
      ZipfileEntry *p;
      for(p=pTab->pFirstEntry; p; p=p->pNext){
        if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){

          rc = SQLITE_CONSTRAINT;
          break;
        }
      }
    }

    if( rc==SQLITE_OK ){







>
>
>
>
>
>
>
|


>







 







|







 







|







 







>







 







|
>
>
>
|
<
>







 







>







 







>







469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
....
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
....
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
....
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
....
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551

1552
1553
1554
1555
1556
1557
1558
1559
....
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
....
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
  return SQLITE_OK;
}

/*
** Set the error message for the virtual table associated with cursor
** pCsr to the results of vprintf(zFmt, ...).
*/
static void zipfileTableErr(ZipfileTab *pTab, const char *zFmt, ...){
  va_list ap;
  va_start(ap, zFmt);
  sqlite3_free(pTab->base.zErrMsg);
  pTab->base.zErrMsg = sqlite3_vmprintf(zFmt, ap);
  va_end(ap);
}
static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){
  va_list ap;
  va_start(ap, zFmt);
  sqlite3_free(pCsr->base.pVtab->zErrMsg);
  pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
  va_end(ap);
}

/*
** Read nRead bytes of data from offset iOff of file pFile into buffer
** aRead[]. Return SQLITE_OK if successful, or an SQLite error code
................................................................................
  int bInMemory = 0;              /* True for an in-memory zipfile */

  zipfileResetCursor(pCsr);

  if( pTab->zFile ){
    zFile = pTab->zFile;
  }else if( idxNum==0 ){
    zipfileCursorErr(pCsr, "zipfile() function requires an argument");
    return SQLITE_ERROR;
  }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
    const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
    int nBlob = sqlite3_value_bytes(argv[0]);
    assert( pTab->pFirstEntry==0 );
    rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
    pCsr->pFreeEntry = pTab->pFirstEntry;
................................................................................
  }else{
    zFile = (const char*)sqlite3_value_text(argv[0]);
  }

  if( 0==pTab->pWriteFd && 0==bInMemory ){
    pCsr->pFile = fopen(zFile, "rb");
    if( pCsr->pFile==0 ){
      zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
      rc = SQLITE_ERROR;
    }else{
      rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
      if( rc==SQLITE_OK ){
        if( pCsr->eocd.nEntry==0 ){
          pCsr->bEof = 1;
        }else{
................................................................................
      if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
      else if( z[i]!='-' ) goto parse_error;
    }
  }
  if( ((mode & S_IFDIR)==0)==bIsDir ){
    /* The "mode" attribute is a directory, but data has been specified.
    ** Or vice-versa - no data but "mode" is a file or symlink.  */
    *pzErr = sqlite3_mprintf("zipfile: mode does not match data");
    return SQLITE_CONSTRAINT;
  }
  *pMode = mode;
  return SQLITE_OK;

 parse_error:
  *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
................................................................................
      }
      assert( pOld->pNext );
    }
  }

  if( nVal>1 ){
    /* Check that "sz" and "rawdata" are both NULL: */
    if( sqlite3_value_type(apVal[5])!=SQLITE_NULL ){
      zipfileTableErr(pTab, "sz must be NULL");
      rc = SQLITE_CONSTRAINT;
    }
    if( sqlite3_value_type(apVal[6])!=SQLITE_NULL ){

      zipfileTableErr(pTab, "rawdata must be NULL"); 
      rc = SQLITE_CONSTRAINT;
    }

    if( rc==SQLITE_OK ){
      if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
        /* data=NULL. A directory */
        bIsDir = 1;
................................................................................
        int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;

        iMethod = sqlite3_value_int(apVal[8]);
        sz = nIn;
        pData = aIn;
        nData = nIn;
        if( iMethod!=0 && iMethod!=8 ){
          zipfileTableErr(pTab, "unknown compression method: %d", iMethod);
          rc = SQLITE_CONSTRAINT;
        }else{
          if( bAuto || iMethod ){
            int nCmp;
            rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg);
            if( rc==SQLITE_OK ){
              if( iMethod || nCmp<nIn ){
................................................................................
    }

    /* Check that we're not inserting a duplicate entry */
    if( pOld==0 && rc==SQLITE_OK ){
      ZipfileEntry *p;
      for(p=pTab->pFirstEntry; p; p=p->pNext){
        if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){
          zipfileTableErr(pTab, "duplicate name: \"%s\"", zPath);
          rc = SQLITE_CONSTRAINT;
          break;
        }
      }
    }

    if( rc==SQLITE_OK ){

Changes to test/zipfile.test.

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
633
634
635
636
637
638
639
640
  5 data {} 0 {} 0
  6 method {} 0 {} 0
}

do_catchsql_test 1.1.0.1 {
  INSERT INTO zz(name, mode, mtime, sz, rawdata, method) 
  VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
} {1 {constraint failed}}
do_catchsql_test 1.1.0.2 {
  INSERT INTO zz(name, mtime, sz, data, method) 
  VALUES('g.txt', 1000000002, 5, '12345', 0);
} {1 {constraint failed}}
do_catchsql_test 1.1.0.3 {
  INSERT INTO zz(name, mtime, rawdata, method) 
  VALUES('g.txt', 1000000002, '12345', 0);
} {1 {constraint failed}}
do_catchsql_test 1.1.0.4 {
  INSERT INTO zz(name, data, method) 
  VALUES('g.txt', '12345', 7);
} {1 {constraint failed}}

do_execsql_test 1.1.1 {
  INSERT INTO zz(name, mode, mtime, data, method) 
  VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
}
do_execsql_test 1.1.2 {
  INSERT INTO zz(name, mode, mtime, data, method) 
................................................................................
  blue.txt/ 16877 1000000000 {} 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_catchsql_test 1.6.7 {
  UPDATE zz SET data=NULL WHERE name='i.txt'
} {1 {constraint failed}}
do_execsql_test 1.6.8 {
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  blue.txt/ 16877 1000000000 {} 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}
................................................................................
foreach {tn fname} {
  1 dir1
  2 file1
  3 dir1/file2
} {
  do_catchsql_test 3.1.$tn.0 {
    INSERT INTO x1(name, data) VALUES($fname, NULL);
  } {1 {constraint failed}}
  do_catchsql_test 3.1.$tn.1 {
    INSERT INTO x1(name, data) VALUES($fname || '/', NULL);
  } {1 {constraint failed}}
  do_catchsql_test 3.1.$tn.2 {
    INSERT INTO x1(name, data) VALUES($fname, 'abcd');
  } {1 {constraint failed}}
}

do_catchsql_test 3.2 {
  SELECT rowid FROM x1
} {1 {no such column: rowid}}

#-------------------------------------------------------------------------
................................................................................
    VALUES('dir3//') UNION ALL
    VALUES('dir4///') UNION ALL
    VALUES('/') 
  )
  SELECT name FROM zipfile((SELECT zipfile(nm, NULL) FROM src))
} {dir1/ dir2/ dir3/ dir4/ /}
finish_test








|



|



|



|







 







|







 







|


|


|







 







<
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
633
634
635
636
637
638
639

  5 data {} 0 {} 0
  6 method {} 0 {} 0
}

do_catchsql_test 1.1.0.1 {
  INSERT INTO zz(name, mode, mtime, sz, rawdata, method) 
  VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
} {1 {rawdata must be NULL}}
do_catchsql_test 1.1.0.2 {
  INSERT INTO zz(name, mtime, sz, data, method) 
  VALUES('g.txt', 1000000002, 5, '12345', 0);
} {1 {sz must be NULL}}
do_catchsql_test 1.1.0.3 {
  INSERT INTO zz(name, mtime, rawdata, method) 
  VALUES('g.txt', 1000000002, '12345', 0);
} {1 {rawdata must be NULL}}
do_catchsql_test 1.1.0.4 {
  INSERT INTO zz(name, data, method) 
  VALUES('g.txt', '12345', 7);
} {1 {unknown compression method: 7}}

do_execsql_test 1.1.1 {
  INSERT INTO zz(name, mode, mtime, data, method) 
  VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
}
do_execsql_test 1.1.2 {
  INSERT INTO zz(name, mode, mtime, data, method) 
................................................................................
  blue.txt/ 16877 1000000000 {} 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_catchsql_test 1.6.7 {
  UPDATE zz SET data=NULL WHERE name='i.txt'
} {1 {zipfile: mode does not match data}}
do_execsql_test 1.6.8 {
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  blue.txt/ 16877 1000000000 {} 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}
................................................................................
foreach {tn fname} {
  1 dir1
  2 file1
  3 dir1/file2
} {
  do_catchsql_test 3.1.$tn.0 {
    INSERT INTO x1(name, data) VALUES($fname, NULL);
  } [list 1 "duplicate name: \"$fname/\""]
  do_catchsql_test 3.1.$tn.1 {
    INSERT INTO x1(name, data) VALUES($fname || '/', NULL);
  } [list 1 "duplicate name: \"$fname/\""]
  do_catchsql_test 3.1.$tn.2 {
    INSERT INTO x1(name, data) VALUES($fname, 'abcd');
  } [list 1 "duplicate name: \"$fname\""]
}

do_catchsql_test 3.2 {
  SELECT rowid FROM x1
} {1 {no such column: rowid}}

#-------------------------------------------------------------------------
................................................................................
    VALUES('dir3//') UNION ALL
    VALUES('dir4///') UNION ALL
    VALUES('/') 
  )
  SELECT name FROM zipfile((SELECT zipfile(nm, NULL) FROM src))
} {dir1/ dir2/ dir3/ dir4/ /}
finish_test