/ Check-in [4068abe0]
Login

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

Overview
Comment:Stylistic fixes: limit source code line length to 80 characters. C89-style comments only, not C++/C99 style.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA1: 4068abe05c3a94c9ac7cff72b77fb8e47a2b1a5d
User & Date: drh 2012-05-17 14:17:13
Context
2012-05-22
13:11
Version 3.7.12.1 check-in: 972e75bb user: drh tags: apple-osx
2012-05-17
14:17
Stylistic fixes: limit source code line length to 80 characters. C89-style comments only, not C++/C99 style. check-in: 4068abe0 user: drh tags: apple-osx
2012-05-16
22:08
Improve error reporting from sqlite3_file_control, SQLITE_FCNTL_REPLACE_DATABASE shouldn't copy file security/ACL metadata, bad bit mask fixed check-in: 92e7bb90 user: adam tags: apple-osx
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
...
542
543
544
545
546
547
548
549




550
551
552
553
554
555
556
....
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
....
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
....
3971
3972
3973
3974
3975
3976
3977
3978
3979

3980






3981
3982
3983
3984
3985
3986
3987
....
3991
3992
3993
3994
3995
3996
3997
3998

3999
4000
4001
4002
4003
4004
4005
....
4043
4044
4045
4046
4047
4048
4049
4050

4051
4052
4053
4054
4055
4056
4057
....
4086
4087
4088
4089
4090
4091
4092
4093

4094
4095
4096

4097
4098
4099
4100
4101
4102
4103
....
4113
4114
4115
4116
4117
4118
4119
4120

4121
4122
4123
4124
4125
4126
4127
....
4704
4705
4706
4707
4708
4709
4710
4711

4712
4713
4714
4715
4716
4717
4718
....
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
....
5126
5127
5128
5129
5130
5131
5132
5133

5134

5135
5136
5137
5138
5139
5140
5141
....
5224
5225
5226
5227
5228
5229
5230
5231

5232
5233
5234
5235
5236
5237
5238
....
5248
5249
5250
5251
5252
5253
5254

5255

5256
5257
5258
5259





5260
5261
5262
5263
5264
5265
5266




5267
5268
5269
5270
5271
5272
5273
....
5274
5275
5276
5277
5278
5279
5280
5281


5282
5283

5284
5285
5286
5287
5288
5289
5290
....
5310
5311
5312
5313
5314
5315
5316

5317
5318
5319
5320
5321
5322
5323
5324
....
5380
5381
5382
5383
5384
5385
5386

5387

5388
5389
5390
5391
5392
5393

5394
5395
5396
5397
5398
5399

5400
5401
5402

5403
5404
5405
5406
5407
5408
5409
....
5413
5414
5415
5416
5417
5418
5419
5420

5421
5422
5423
5424
5425
5426
5427
....
6303
6304
6305
6306
6307
6308
6309
6310

6311
6312
6313
6314
6315
6316
6317
....
7299
7300
7301
7302
7303
7304
7305

7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
....
7453
7454
7455
7456
7457
7458
7459
7460

7461
7462
7463
7464
7465
7466
7467
....
7672
7673
7674
7675
7676
7677
7678
7679

7680
7681
7682
7683
7684
7685
7686
*/
static void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);

    if( rc==SQLITE_OK ){
      fd->pMethods->xShmLock(fd, 2, 1, flags);
      fd->pMethods->xShmLock(fd, 3, SQLITE_SHM_NLOCK-3, flags);
    }
  }
  sqlite3_close(p->db);
  sqlite3_free(p);
................................................................................
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
static int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */
  int flags,                      /* Additional flags to pass to sqlite3_open_v2 */
  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;
................................................................................
  return rc;
}

/* A corrupt DB won't work with the sql-based locking attempt, grab an 
** exclusive lock and return SQLITE_OK or SQLITE_BUSY if the lock fails 
** returns the current lock level held on sqlite3_file
*/
static int sqlite3demo_superlock_corrupt(sqlite3_file *id, int eTargetFileLock, int *pFileLock) {




  unixFile *pFile = (unixFile*)id;
  int eFileLock = pFile->eFileLock;
  int rc = SQLITE_OK;
  
  if( eFileLock<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
  }
................................................................................
  got = seekAndRead(pFile, offset, pBuf, amt);
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    /* lastErrno set by seekAndRead */
    return SQLITE_IOERR_READ;
  }else{
    //storeLastErrno(pFile, 0); /* not a system error, but we want to preserve lastErrno */
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[got], 0, amt-got);
    return SQLITE_IOERR_SHORT_READ;
  }
}

/*
................................................................................
  SimulateDiskfullError(( wrote=0, amt=1 ));

  if( amt>0 ){
    if( wrote<0 && pFile->lastErrno!=ENOSPC ){
      /* lastErrno set by seekAndWrite */
      return SQLITE_IOERR_WRITE;
    }else{
      //storeLastErrno(pFile, 0); /* not a system error, but we want to preserve lastErrno */
      return SQLITE_FULL;
    }
  }

  return SQLITE_OK;
}

................................................................................
static int unixTruncateDatabase(unixFile *, int);

static int unixInvalidateSupportFiles(unixFile *, int);

static int findCreateFileMode(const char *, int, mode_t*, uid_t *,gid_t *);

/* opens a read/write connection to a file zName inheriting the appropriate
 ** user/perms from the database file if running as root.  Returns the file 
 ** descriptor by reference */

static int unixOpenChildFile(const char *zName, int openFlags, int dbOpenFlags, int protFlags, int *pFd) {






  int fd = -1;
  mode_t openMode;              /* Permissions to create file with */
  uid_t uid;                    /* Userid for the file */
  gid_t gid;                    /* Groupid for the file */
  int rc;
  
  assert(pFd!=NULL);
................................................................................
  }
  fd = robust_open(zName, openFlags, openMode);
  OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
  if( fd<0 ){
    rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    return rc;
  }
  /* if we're opening the wal or journal and running as root, set the journal uid/gid */

  if( dbOpenFlags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    uid_t euid = geteuid();
    if( euid==0 && (euid!=uid || getegid()!=gid) ){
      if( fchown(fd, uid, gid) ){
        rc = SQLITE_CANTOPEN_BKPT;
      }
    }
................................................................................
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isDstCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);

    }
    if( rc ){
      return rc;
    }
  }
  /* get the src file descriptor adhering to the db struct access rules 
   ** this code is modeled after sqlite3_file_control() in main.c
................................................................................
      if( isProxyLockingMode(pSrcFile) ){
        srcFlags |= SQLITE_OPEN_AUTOPROXY;
      }
#endif
      rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
      if( rc==SQLITE_OK ){
        /* start a deferred transaction and read to establish a read lock */
        rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0);

        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
          isSrcCorrupt = 1;
          rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock);

        }
      }
    }
  }
  if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
    rc = SQLITE_INTERNAL;
  }
................................................................................
  if( !(srcWalFD<0) ){
    char dstWalPath[MAXPATHLEN+5];
    int dstWalFD = -1;
    int protFlags = 0;
    strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
    strlcat(dstWalPath, "-wal", MAXPATHLEN+5);

    rc = unixOpenChildFile(dstWalPath, O_RDWR|O_CREAT, SQLITE_OPEN_WAL, protFlags, &dstWalFD);

    if( rc==SQLITE_OK ){
      s = copyfile_state_alloc();
      lseek(srcWalFD, 0, SEEK_SET);
      lseek(dstWalFD, 0, SEEK_SET);
      if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_DATA) ){
        int err=errno;
        switch(err) {
................................................................................
      ** If not, truncate the file to zero length. 
      */
      rc = SQLITE_OK;
      if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
        if( robust_ftruncate(pShmNode->h, 0) ){
          rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
        }else{
          /* If running as root set the uid/gid of the shm file to match the database */

          uid_t euid = geteuid();
          if( euid==0 && (euid!=sStat.st_uid || getegid()!=sStat.st_gid) ){
            if( fchown(pShmNode->h, sStat.st_uid, sStat.st_gid) ){
              rc = SQLITE_IOERR_SHMOPEN;
            }
          }
        }
................................................................................
  assert( pShmNode->nRef>0 );
  pShmNode->nRef--;
  if( pShmNode->nRef==0 ){
    if( deleteFlag && pShmNode->h>=0 ) {
      if (deleteFlag == 1) { 
        unlink(pShmNode->zFilename);
      } else if (deleteFlag == 2) {
        //ftruncate(pShmNode->h, 32 * 1024);
      }
    }
    
    unixShmPurge(pDbFd);
  }
  unixLeaveMutex();

................................................................................
      }
    }
  }
  return SQLITE_OK;
}

static int unixUnsafeTruncateDatabase(unixFile *pFile){
  // this is nasty & bad.  destruction with prejudice.  we'll lose all the file locks in this process, however.

  // sqlite3_file_control works properly.  But if it fails, this works approximately

  char journalPath[MAXPATHLEN];
  char walPath[MAXPATHLEN];
  int rc = SQLITE_OK;
  
#ifdef DEBUG
  fprintf(stderr, "Force truncating database %s\n", pFile->zPath);
#endif
................................................................................
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);

    }
    if( rc && !force ){
      return rc;
    }
    rc = SQLITE_OK; /* Ignore the locking failure if force is true */
  }
  if( (bFlags&SQLITE_TRUNCATE_INITIALIZE_HEADER_MASK)!=0 ){
................................................................................
    if( tFd==-1 ){
      storeLastErrno(pFile, errno);
      rc = SQLITE_IOERR;
      safeFailed = 1;
    }else{
      sqlite3 *tDb = NULL;
      copyfile_state_t s;

      int trc = sqlite3_open_v2(tDbPath, &tDb, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_AUTOPROXY, NULL);

      char *errmsg = NULL;
      const char *sql = "";
      if( !trc && (bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) ){
        const char pagesize_sql[4][22] = { "pragma page_size=1024", "pragma page_size=2048", "pragma page_size=4096", "pragma page_size=8192" };





        int iPagesize = (((bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) >> 4) - 1);
        assert( iPagesize>=0 && iPagesize<=4 );
        sql = pagesize_sql[iPagesize];
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( !trc ){
        const char autovacuum_sql[3][21] = { "pragma auto_vacuum=0", "pragma auto_vacuum=1", "pragma auto_vacuum=2" };




        int iAutovacuum = 2; /* default to incremental */
        if( (bFlags&SQLITE_TRUNCATE_AUTOVACUUM_MASK) ){
          iAutovacuum = (((bFlags&SQLITE_TRUNCATE_AUTOVACUUM_MASK) >> 2) - 1);
        }
        assert( iAutovacuum>=0 && iAutovacuum<=2 );
        sql = autovacuum_sql[iAutovacuum];
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
................................................................................
      }
      if( !trc && (bFlags&SQLITE_TRUNCATE_JOURNALMODE_WAL) ){
        sql = "pragma journal_mode=wal";
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( trc ){
        if( !tDb ){
          fprintf(stderr, "failed to open temp database '%s' to reset truncated database %s with flags %x: %d\n", tDbPath, pFile->zPath, bFlags, trc);


        }else{
          fprintf(stderr, "failed to set '%s' on truncated database %s, %d: %s\n", sql, pFile->zPath, trc, errmsg);

        }
      }
      if( tDb ){
        int off = 0;
        /* merge the wal into the db */
        sqlite3_file_control(tDb, NULL, SQLITE_FCNTL_PERSIST_WAL, &off);
        sqlite3_close(tDb);
................................................................................
      if( trc!=SQLITE_OK ){
        safeFailed = 1;
        rc = trc;
      }
    }
    free(tDbPath);
  } else {

    rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
    if( rc ){
      safeFailed = 1;
    }
  }
  if( rc==SQLITE_OK || force ){
    rc = unixInvalidateSupportFiles(pFile, 0);
    if( rc ){
................................................................................
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  if( got==0 ){
    noHdr = 1;

  }else if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){

    *pLockstate = SQLITE_LOCKSTATE_NOTADB;
    return SQLITE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");

  if (!noHdr) {
    isWal = aHdr[18]==2;
  }
  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");

  }
  if( nLock==0 && isWal!=0 ){
    /* lookup the file descriptor for the shared memory file if we have it open in this process */

    unixEnterMutex(); /* Because pFile->pInode is shared across threads */
    unixShmNode *pShmNode = pFile->pInode->pShmNode;
    if( pShmNode ){
      sqlite3_mutex_enter(pShmNode->mutex);
      
      hShm = pShmNode->h;
      if( hShm >= 0){
................................................................................
        }
      }
      
      sqlite3_mutex_leave(pShmNode->mutex);
    } 
    
    if( hShm<0 ){
      /* the shared memory file isn't open in this process space, open our own FD */

      char zShm[MAXPATHLEN];
      
      /* WAL mode */
      strlcpy(zShm, pFile->zPath, MAXPATHLEN);
      strlcat(zShm, "-shm", MAXPATHLEN);
      hShm = open(zShm, O_RDONLY, 0);
      if( hShm<0 ){
................................................................................
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }
    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      goto open_finished;
    }
    /* if we're opening the wal or journal and running as root, set the journal uid/gid */

    if( !isReadonly && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL)) ){
      uid_t euid = geteuid();
      if( euid==0 && (euid!=uid || getegid()!=gid) ){
        if( fchown(fd, uid, gid) ){
          rc = SQLITE_CANTOPEN_BKPT;
          goto open_finished;
        }
................................................................................
            uuid_t conchUUID;
            uuid_string_t conchUUIDString;
            uuid_string_t myUUIDString;
            assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
            memcpy(conchUUID, &tBuf[PROXY_HEADERLEN], PROXY_HOSTIDLEN);
            uuid_unparse(conchUUID, conchUUIDString);
            uuid_unparse(myHostID, myUUIDString);

            fprintf(stderr, "ERROR: sqlite database is locked because it is in use "
                    "by another host that holds a host-exclusive lock on %s; "
                    "this host (UUID %s) cannot override the host-exclusive lock "
                    "until the other host (UUID %s) releases its locks on %s\n", 
                    pFile->zPath, myUUIDString, conchUUIDString, conchFile->zPath);
            return SQLITE_BUSY;
          }
        }else{
          /* don't break the lock on short read or a version mismatch */
          return SQLITE_BUSY;
        }
        usleep(10000000); /* wait 10 sec and try the lock again */
................................................................................
      if( rc==SQLITE_OK ){
        char writeBuffer[PROXY_MAXCONCHLEN];
        int writeSize = 0;
        
        writeBuffer[0] = (char)PROXY_CONCHVERSION;
        memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
        if( pCtx->lockProxyPath!=NULL ){
          strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN);

        }else{
          strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
        }
        writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
        robust_ftruncate(conchFile->h, writeSize);
        rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
        fsync(conchFile->h);
................................................................................
*/
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath){
#if defined(__APPLE__)
  if( pFile->pMethod == &afpIoMethods ){
    /* afp style keeps a reference to the db path in the filePath field 
    ** of the struct */
    assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
    strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN);

  } else
#endif
  if( pFile->pMethod == &dotlockIoMethods ){
    /* dot lock style uses the locking context to store the dot lock
    ** file path */
    int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX);
    memcpy(dbPath, (char *)pFile->lockingContext, len + 1);







|
>







 







|







 







|
>
>
>
>







 







<







 







<







 







|
|
>
|
>
>
>
>
>
>







 







|
>







 







|
>







 







|
>


|
>







 







|
>







 







|
>







 







|







 







|
>
|
>







 







|
>







 







>
|
>



|
>
>
>
>
>






|
>
>
>
>







 







|
>
>

|
>







 







>
|







 







>
|
>





|
>





|
>


|
>







 







|
>







 







|
>







 







>
|
|
|
|
|







 







|
>







 







|
>







444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
....
3469
3470
3471
3472
3473
3474
3475

3476
3477
3478
3479
3480
3481
3482
....
3576
3577
3578
3579
3580
3581
3582

3583
3584
3585
3586
3587
3588
3589
....
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
....
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
....
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
....
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
....
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
....
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
....
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
....
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
....
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
....
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
....
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
....
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
....
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
....
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
....
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
....
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
....
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
....
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
*/
static void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER,
                             (void *)&fd);
    if( rc==SQLITE_OK ){
      fd->pMethods->xShmLock(fd, 2, 1, flags);
      fd->pMethods->xShmLock(fd, 3, SQLITE_SHM_NLOCK-3, flags);
    }
  }
  sqlite3_close(p->db);
  sqlite3_free(p);
................................................................................
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
static int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */
  int flags,                   /* Additional flags to pass to sqlite3_open_v2 */
  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;
................................................................................
  return rc;
}

/* A corrupt DB won't work with the sql-based locking attempt, grab an 
** exclusive lock and return SQLITE_OK or SQLITE_BUSY if the lock fails 
** returns the current lock level held on sqlite3_file
*/
static int sqlite3demo_superlock_corrupt(
  sqlite3_file *id,
  int eTargetFileLock,
  int *pFileLock
){
  unixFile *pFile = (unixFile*)id;
  int eFileLock = pFile->eFileLock;
  int rc = SQLITE_OK;
  
  if( eFileLock<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
  }
................................................................................
  got = seekAndRead(pFile, offset, pBuf, amt);
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    /* lastErrno set by seekAndRead */
    return SQLITE_IOERR_READ;
  }else{

    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[got], 0, amt-got);
    return SQLITE_IOERR_SHORT_READ;
  }
}

/*
................................................................................
  SimulateDiskfullError(( wrote=0, amt=1 ));

  if( amt>0 ){
    if( wrote<0 && pFile->lastErrno!=ENOSPC ){
      /* lastErrno set by seekAndWrite */
      return SQLITE_IOERR_WRITE;
    }else{

      return SQLITE_FULL;
    }
  }

  return SQLITE_OK;
}

................................................................................
static int unixTruncateDatabase(unixFile *, int);

static int unixInvalidateSupportFiles(unixFile *, int);

static int findCreateFileMode(const char *, int, mode_t*, uid_t *,gid_t *);

/* opens a read/write connection to a file zName inheriting the appropriate
** user/perms from the database file if running as root.  Returns the file 
** descriptor by reference
*/
static int unixOpenChildFile(
  const char *zName,
  int openFlags,
  int dbOpenFlags,
  int protFlags,
  int *pFd
){
  int fd = -1;
  mode_t openMode;              /* Permissions to create file with */
  uid_t uid;                    /* Userid for the file */
  gid_t gid;                    /* Groupid for the file */
  int rc;
  
  assert(pFd!=NULL);
................................................................................
  }
  fd = robust_open(zName, openFlags, openMode);
  OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
  if( fd<0 ){
    rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    return rc;
  }
  /* if we're opening the wal or journal and running as root, set
  ** the journal uid/gid */
  if( dbOpenFlags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    uid_t euid = geteuid();
    if( euid==0 && (euid!=uid || getegid()!=gid) ){
      if( fchown(fd, uid, gid) ){
        rc = SQLITE_CANTOPEN_BKPT;
      }
    }
................................................................................
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isDstCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE,
                                         &corruptDstFileLock);
    }
    if( rc ){
      return rc;
    }
  }
  /* get the src file descriptor adhering to the db struct access rules 
   ** this code is modeled after sqlite3_file_control() in main.c
................................................................................
      if( isProxyLockingMode(pSrcFile) ){
        srcFlags |= SQLITE_OPEN_AUTOPROXY;
      }
#endif
      rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
      if( rc==SQLITE_OK ){
        /* start a deferred transaction and read to establish a read lock */
        rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version",
                          0, 0, 0);
        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
          isSrcCorrupt = 1;
          rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED,
                                             &corruptSrcFileLock);
        }
      }
    }
  }
  if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
    rc = SQLITE_INTERNAL;
  }
................................................................................
  if( !(srcWalFD<0) ){
    char dstWalPath[MAXPATHLEN+5];
    int dstWalFD = -1;
    int protFlags = 0;
    strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
    strlcat(dstWalPath, "-wal", MAXPATHLEN+5);

    rc = unixOpenChildFile(dstWalPath, O_RDWR|O_CREAT, SQLITE_OPEN_WAL,
                           protFlags, &dstWalFD);
    if( rc==SQLITE_OK ){
      s = copyfile_state_alloc();
      lseek(srcWalFD, 0, SEEK_SET);
      lseek(dstWalFD, 0, SEEK_SET);
      if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_DATA) ){
        int err=errno;
        switch(err) {
................................................................................
      ** If not, truncate the file to zero length. 
      */
      rc = SQLITE_OK;
      if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
        if( robust_ftruncate(pShmNode->h, 0) ){
          rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
        }else{
          /* If running as root set the uid/gid of the shm file to match
          ** the database */
          uid_t euid = geteuid();
          if( euid==0 && (euid!=sStat.st_uid || getegid()!=sStat.st_gid) ){
            if( fchown(pShmNode->h, sStat.st_uid, sStat.st_gid) ){
              rc = SQLITE_IOERR_SHMOPEN;
            }
          }
        }
................................................................................
  assert( pShmNode->nRef>0 );
  pShmNode->nRef--;
  if( pShmNode->nRef==0 ){
    if( deleteFlag && pShmNode->h>=0 ) {
      if (deleteFlag == 1) { 
        unlink(pShmNode->zFilename);
      } else if (deleteFlag == 2) {
        /* ftruncate(pShmNode->h, 32 * 1024); */
      }
    }
    
    unixShmPurge(pDbFd);
  }
  unixLeaveMutex();

................................................................................
      }
    }
  }
  return SQLITE_OK;
}

static int unixUnsafeTruncateDatabase(unixFile *pFile){
  /* this is nasty & bad.  destruction with prejudice.  we'll lose all the
  ** file locks in this process, however. sqlite3_file_control works properly.
  ** But if it fails, this works approximately
  */
  char journalPath[MAXPATHLEN];
  char walPath[MAXPATHLEN];
  int rc = SQLITE_OK;
  
#ifdef DEBUG
  fprintf(stderr, "Force truncating database %s\n", pFile->zPath);
#endif
................................................................................
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE,
                                         &corruptFileLock);
    }
    if( rc && !force ){
      return rc;
    }
    rc = SQLITE_OK; /* Ignore the locking failure if force is true */
  }
  if( (bFlags&SQLITE_TRUNCATE_INITIALIZE_HEADER_MASK)!=0 ){
................................................................................
    if( tFd==-1 ){
      storeLastErrno(pFile, errno);
      rc = SQLITE_IOERR;
      safeFailed = 1;
    }else{
      sqlite3 *tDb = NULL;
      copyfile_state_t s;
      int trc = sqlite3_open_v2(tDbPath, &tDb,
                   (SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
                      | SQLITE_OPEN_AUTOPROXY), NULL);
      char *errmsg = NULL;
      const char *sql = "";
      if( !trc && (bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) ){
        const char pagesize_sql[4][22] = {
          "pragma page_size=1024",
          "pragma page_size=2048",
          "pragma page_size=4096",
          "pragma page_size=8192" 
        };
        int iPagesize = (((bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) >> 4) - 1);
        assert( iPagesize>=0 && iPagesize<=4 );
        sql = pagesize_sql[iPagesize];
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( !trc ){
        const char autovacuum_sql[3][21] = {
          "pragma auto_vacuum=0",
          "pragma auto_vacuum=1",
          "pragma auto_vacuum=2"
        };
        int iAutovacuum = 2; /* default to incremental */
        if( (bFlags&SQLITE_TRUNCATE_AUTOVACUUM_MASK) ){
          iAutovacuum = (((bFlags&SQLITE_TRUNCATE_AUTOVACUUM_MASK) >> 2) - 1);
        }
        assert( iAutovacuum>=0 && iAutovacuum<=2 );
        sql = autovacuum_sql[iAutovacuum];
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
................................................................................
      }
      if( !trc && (bFlags&SQLITE_TRUNCATE_JOURNALMODE_WAL) ){
        sql = "pragma journal_mode=wal";
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( trc ){
        if( !tDb ){
          fprintf(stderr, "failed to open temp database '%s' to reset "
                          "truncated database %s with flags %x: %d\n",
                           tDbPath, pFile->zPath, bFlags, trc);
        }else{
          fprintf(stderr, "failed to set '%s' on truncated database %s, %d: "
                          "%s\n", sql, pFile->zPath, trc, errmsg);
        }
      }
      if( tDb ){
        int off = 0;
        /* merge the wal into the db */
        sqlite3_file_control(tDb, NULL, SQLITE_FCNTL_PERSIST_WAL, &off);
        sqlite3_close(tDb);
................................................................................
      if( trc!=SQLITE_OK ){
        safeFailed = 1;
        rc = trc;
      }
    }
    free(tDbPath);
  } else {
    rc = pFile->pMethod->xTruncate(id, 
           ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
    if( rc ){
      safeFailed = 1;
    }
  }
  if( rc==SQLITE_OK || force ){
    rc = unixInvalidateSupportFiles(pFile, 0);
    if( rc ){
................................................................................
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  if( got==0 ){
    noHdr = 1;
  }else if( got!=100
         || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0
  ){
    *pLockstate = SQLITE_LOCKSTATE_NOTADB;
    return SQLITE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE,
                        "EXCLUSIVE");
  if (!noHdr) {
    isWal = aHdr[18]==2;
  }
  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2,
                          "PENDING|RESERVED|SHARED");
  }
  if( nLock==0 && isWal!=0 ){
    /* lookup the file descriptor for the shared memory file if we have it open
    ** in this process */
    unixEnterMutex(); /* Because pFile->pInode is shared across threads */
    unixShmNode *pShmNode = pFile->pInode->pShmNode;
    if( pShmNode ){
      sqlite3_mutex_enter(pShmNode->mutex);
      
      hShm = pShmNode->h;
      if( hShm >= 0){
................................................................................
        }
      }
      
      sqlite3_mutex_leave(pShmNode->mutex);
    } 
    
    if( hShm<0 ){
      /* the shared memory file isn't open in this process space, open our
      ** own FD */
      char zShm[MAXPATHLEN];
      
      /* WAL mode */
      strlcpy(zShm, pFile->zPath, MAXPATHLEN);
      strlcat(zShm, "-shm", MAXPATHLEN);
      hShm = open(zShm, O_RDONLY, 0);
      if( hShm<0 ){
................................................................................
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }
    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      goto open_finished;
    }
    /* if we're opening the wal or journal and running as root, set the
    ** journal uid/gid */
    if( !isReadonly && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL)) ){
      uid_t euid = geteuid();
      if( euid==0 && (euid!=uid || getegid()!=gid) ){
        if( fchown(fd, uid, gid) ){
          rc = SQLITE_CANTOPEN_BKPT;
          goto open_finished;
        }
................................................................................
            uuid_t conchUUID;
            uuid_string_t conchUUIDString;
            uuid_string_t myUUIDString;
            assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
            memcpy(conchUUID, &tBuf[PROXY_HEADERLEN], PROXY_HOSTIDLEN);
            uuid_unparse(conchUUID, conchUUIDString);
            uuid_unparse(myHostID, myUUIDString);
            fprintf(stderr,
               "ERROR: sqlite database is locked because it is in use "
               "by another host that holds a host-exclusive lock on %s; "
               "this host (UUID %s) cannot override the host-exclusive lock "
               "until the other host (UUID %s) releases its locks on %s\n", 
               pFile->zPath, myUUIDString, conchUUIDString, conchFile->zPath);
            return SQLITE_BUSY;
          }
        }else{
          /* don't break the lock on short read or a version mismatch */
          return SQLITE_BUSY;
        }
        usleep(10000000); /* wait 10 sec and try the lock again */
................................................................................
      if( rc==SQLITE_OK ){
        char writeBuffer[PROXY_MAXCONCHLEN];
        int writeSize = 0;
        
        writeBuffer[0] = (char)PROXY_CONCHVERSION;
        memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
        if( pCtx->lockProxyPath!=NULL ){
          strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath,
                  MAXPATHLEN);
        }else{
          strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
        }
        writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
        robust_ftruncate(conchFile->h, writeSize);
        rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
        fsync(conchFile->h);
................................................................................
*/
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath){
#if defined(__APPLE__)
  if( pFile->pMethod == &afpIoMethods ){
    /* afp style keeps a reference to the db path in the filePath field 
    ** of the struct */
    assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
    strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath,
            MAXPATHLEN);
  } else
#endif
  if( pFile->pMethod == &dotlockIoMethods ){
    /* dot lock style uses the locking context to store the dot lock
    ** file path */
    int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX);
    memcpy(dbPath, (char *)pFile->lockingContext, len + 1);