/ Check-in [e5d180ee]
Login

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

Overview
Comment:On unix, try to create the *-wal and *-shm files with the same permissions as the associated database file.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:e5d180eed245437b61bfb257ee01e2571c93afe7
User & Date: dan 2010-07-14 14:48:58
Context
2010-07-14
16:37
Test the libraries response to read-only or unreadable database, WAL and wal-index files. If a WAL file cannot be opened in read/write mode, return SQLITE_CANTOPEN to the caller. check-in: 45bb84c6 user: dan tags: trunk
14:48
On unix, try to create the *-wal and *-shm files with the same permissions as the associated database file. check-in: e5d180ee user: dan tags: trunk
08:20
Add tests to pagerfault.test. check-in: b092f2a7 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os.c.

   128    128     const char *zPath, 
   129    129     sqlite3_file *pFile, 
   130    130     int flags, 
   131    131     int *pFlagsOut
   132    132   ){
   133    133     int rc;
   134    134     DO_OS_MALLOC_TEST(0);
   135         -  /* 0x7f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
          135  +  /* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
   136    136     ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
   137    137     ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
   138    138     ** reaching the VFS. */
   139         -  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f3f, pFlagsOut);
          139  +  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f3f, pFlagsOut);
   140    140     assert( rc==SQLITE_OK || pFile->pMethods==0 );
   141    141     return rc;
   142    142   }
   143    143   int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
   144    144     return pVfs->xDelete(pVfs, zPath, dirSync);
   145    145   }
   146    146   int sqlite3OsAccess(

Changes to src/os_unix.c.

  3311   3311     /* Check to see if a unixShmNode object already exists. Reuse an existing
  3312   3312     ** one if present. Create a new one if necessary.
  3313   3313     */
  3314   3314     unixEnterMutex();
  3315   3315     pInode = pDbFd->pInode;
  3316   3316     pShmNode = pInode->pShmNode;
  3317   3317     if( pShmNode==0 ){
         3318  +    struct stat sStat;                 /* fstat() info for database file */
         3319  +
         3320  +    /* Call fstat() to figure out the permissions on the database file. If
         3321  +    ** a new *-shm file is created, an attempt will be made to create it
         3322  +    ** with the same permissions. The actual permissions the file is created
         3323  +    ** with are subject to the current umask setting.
         3324  +    */
         3325  +    if( fstat(pDbFd->h, &sStat) ){
         3326  +      rc = SQLITE_IOERR_FSTAT;
         3327  +      goto shm_open_err;
         3328  +    }
         3329  +
  3318   3330       nShmFilename = 5 + (int)strlen(pDbFd->zPath);
  3319   3331       pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
  3320   3332       if( pShmNode==0 ){
  3321   3333         rc = SQLITE_NOMEM;
  3322   3334         goto shm_open_err;
  3323   3335       }
  3324   3336       memset(pShmNode, 0, sizeof(*pShmNode));
................................................................................
  3329   3341       pShmNode->pInode = pDbFd->pInode;
  3330   3342       pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
  3331   3343       if( pShmNode->mutex==0 ){
  3332   3344         rc = SQLITE_NOMEM;
  3333   3345         goto shm_open_err;
  3334   3346       }
  3335   3347   
  3336         -    pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, 0664);
         3348  +    pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777));
  3337   3349       if( pShmNode->h<0 ){
  3338   3350         rc = SQLITE_CANTOPEN_BKPT;
  3339   3351         goto shm_open_err;
  3340   3352       }
  3341   3353   
  3342   3354       /* Check to see if another process is holding the dead-man switch.
  3343   3355       ** If not, truncate the file to zero length. 
................................................................................
  4285   4297         }
  4286   4298       }
  4287   4299       unixLeaveMutex();
  4288   4300     }
  4289   4301   #endif    /* if !OS_VXWORKS */
  4290   4302     return pUnused;
  4291   4303   }
         4304  +
         4305  +/*
         4306  +** This function is called by unixOpen() to determine the unix permissions
         4307  +** to create new files with. If no error occurs, then SQLite is returned
         4308  +** and a value suitable for passing as the third argument to open(2) is
         4309  +** written to *pMode. If an IO error occurs, an SQLite error code is 
         4310  +** returned and the value of *pMode is not modified.
         4311  +**
         4312  +** If the file being opened is a temporary file, it is always created with
         4313  +** the octal permissions 0600 (read/writable by owner only). If the file
         4314  +** is a database, journal or master journal file, it is created with the
         4315  +** permissions mask SQLITE_DEFAULT_FILE_PERMISSIONS.
         4316  +**
         4317  +** Finally, if the file being opened is a WAL file, then this function
         4318  +** queries the file-system for the permissions on the corresponding database
         4319  +** file and sets *pMode to this value. Whenever possible, WAL files are 
         4320  +** created using the same permissions as the associated database file.
         4321  +*/
         4322  +static int findCreateFileMode(
         4323  +  const char *zPath,              /* Path of file (possibly) being created */
         4324  +  int flags,                      /* Flags passed as 4th argument to xOpen() */
         4325  +  mode_t *pMode                   /* OUT: Permissions to open file with */
         4326  +){
         4327  +  int rc = SQLITE_OK;             /* Return Code */
         4328  +  if( flags & SQLITE_OPEN_WAL ){
         4329  +    char zDb[MAX_PATHNAME+1];     /* Database file path */
         4330  +    int nDb;                      /* Number of valid bytes in zDb */
         4331  +    struct stat sStat;            /* Output of stat() on database file */
         4332  +
         4333  +    nDb = sqlite3Strlen30(zPath) - 4;
         4334  +    memcpy(zDb, zPath, nDb);
         4335  +    zDb[nDb] = '\0';
         4336  +    if( 0==stat(zDb, &sStat) ){
         4337  +      *pMode = sStat.st_mode & 0777;
         4338  +    }else{
         4339  +      rc = SQLITE_IOERR_FSTAT;
         4340  +    }
         4341  +  }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
         4342  +    *pMode = 0600;
         4343  +  }else{
         4344  +    *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
         4345  +  }
         4346  +  return rc;
         4347  +}
  4292   4348   
  4293   4349   /*
  4294   4350   ** Open the file zPath.
  4295   4351   ** 
  4296   4352   ** Previously, the SQLite OS layer used three functions in place of this
  4297   4353   ** one:
  4298   4354   **
................................................................................
  4336   4392     int isAutoProxy  = (flags & SQLITE_OPEN_AUTOPROXY);
  4337   4393   #endif
  4338   4394   
  4339   4395     /* If creating a master or main-file journal, this function will open
  4340   4396     ** a file-descriptor on the directory too. The first time unixSync()
  4341   4397     ** is called the directory file descriptor will be fsync()ed and close()d.
  4342   4398     */
  4343         -  int isOpenDirectory = (isCreate && 
  4344         -      (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL)
  4345         -  );
         4399  +  int isOpenDirectory = (isCreate && (
         4400  +        eType==SQLITE_OPEN_MASTER_JOURNAL 
         4401  +     || eType==SQLITE_OPEN_MAIN_JOURNAL 
         4402  +     || eType==SQLITE_OPEN_WAL
         4403  +  ));
  4346   4404   
  4347   4405     /* If argument zPath is a NULL pointer, this function is required to open
  4348   4406     ** a temporary file. Use this buffer to store the file name in.
  4349   4407     */
  4350   4408     char zTmpname[MAX_PATHNAME+1];
  4351   4409     const char *zName = zPath;
  4352   4410   
................................................................................
  4358   4416     **   (d) if DELETEONCLOSE is set, then CREATE must also be set.
  4359   4417     */
  4360   4418     assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
  4361   4419     assert(isCreate==0 || isReadWrite);
  4362   4420     assert(isExclusive==0 || isCreate);
  4363   4421     assert(isDelete==0 || isCreate);
  4364   4422   
  4365         -  /* The main DB, main journal, and master journal are never automatically
  4366         -  ** deleted. Nor are they ever temporary files.  */
         4423  +  /* The main DB, main journal, WAL file and master journal are never 
         4424  +  ** automatically deleted. Nor are they ever temporary files.  */
  4367   4425     assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
  4368   4426     assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
  4369   4427     assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
         4428  +  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
  4370   4429   
  4371   4430     /* Assert that the upper layer has set one of the "file-type" flags. */
  4372   4431     assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
  4373   4432          || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
  4374   4433          || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
  4375         -       || eType==SQLITE_OPEN_TRANSIENT_DB
         4434  +       || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
  4376   4435     );
  4377   4436   
  4378   4437     memset(p, 0, sizeof(unixFile));
  4379   4438   
  4380   4439     if( eType==SQLITE_OPEN_MAIN_DB ){
  4381   4440       UnixUnusedFd *pUnused;
  4382   4441       pUnused = findReusableFd(zName, flags);
................................................................................
  4406   4465     if( isReadonly )  openFlags |= O_RDONLY;
  4407   4466     if( isReadWrite ) openFlags |= O_RDWR;
  4408   4467     if( isCreate )    openFlags |= O_CREAT;
  4409   4468     if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  4410   4469     openFlags |= (O_LARGEFILE|O_BINARY);
  4411   4470   
  4412   4471     if( fd<0 ){
  4413         -    mode_t openMode = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
         4472  +    mode_t openMode;              /* Permissions to create file with */
         4473  +    rc = findCreateFileMode(zName, flags, &openMode);
         4474  +    if( rc!=SQLITE_OK ){
         4475  +      assert( !p->pUnused );
         4476  +      return rc;
         4477  +    }
  4414   4478       fd = open(zName, openFlags, openMode);
  4415   4479       OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
  4416   4480       if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
  4417   4481         /* Failed to open the file for read/write access. Try read-only. */
  4418   4482         flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
  4419   4483         openFlags &= ~(O_RDWR|O_CREAT);
  4420   4484         flags |= SQLITE_OPEN_READONLY;

Changes to src/sqlite.h.in.

   472    472   #define SQLITE_OPEN_TEMP_JOURNAL     0x00001000  /* VFS only */
   473    473   #define SQLITE_OPEN_SUBJOURNAL       0x00002000  /* VFS only */
   474    474   #define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */
   475    475   #define SQLITE_OPEN_NOMUTEX          0x00008000  /* Ok for sqlite3_open_v2() */
   476    476   #define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
   477    477   #define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
   478    478   #define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
          479  +#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */
   479    480   
   480    481   /*
   481    482   ** CAPI3REF: Device Characteristics
   482    483   **
   483    484   ** The xDeviceCharacteristics method of the [sqlite3_io_methods]
   484    485   ** object returns an integer which is a vector of the these
   485    486   ** bit values expressing I/O characteristics of the mass storage

Changes to src/wal.c.

  1220   1220     pRet->pVfs = pVfs;
  1221   1221     pRet->pWalFd = (sqlite3_file *)&pRet[1];
  1222   1222     pRet->pDbFd = pDbFd;
  1223   1223     pRet->readLock = -1;
  1224   1224     pRet->zWalName = zWalName;
  1225   1225   
  1226   1226     /* Open file handle on the write-ahead log file. */
  1227         -  flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_JOURNAL);
         1227  +  flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
  1228   1228     rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
  1229   1229   
  1230   1230     if( rc!=SQLITE_OK ){
  1231   1231       walIndexClose(pRet, 0);
  1232   1232       sqlite3OsClose(pRet->pWalFd);
  1233   1233       sqlite3_free(pRet);
  1234   1234     }else{

Changes to test/wal2.test.

   993    993   do_test wal2-12.1 {
   994    994     catchsql { INSERT INTO t1 VALUES(10, 11, 12) }
   995    995   } {1 {database disk image is malformed}}
   996    996   
   997    997   db close
   998    998   db2 close
   999    999   tvfs delete
         1000  +
         1001  +#-------------------------------------------------------------------------
         1002  +# If a connection is required to create a WAL or SHM file, it creates 
         1003  +# the new files with the same file-system permissions as the database 
         1004  +# file itself. Test this.
         1005  +#
         1006  +if {$::tcl_platform(platform) == "unix"} {
         1007  +  faultsim_delete_and_reopen
         1008  +
         1009  +  set umask [exec /bin/sh -c umask]
         1010  +  do_test wal2-12.1 {
         1011  +    sqlite3 db test.db
         1012  +    execsql { 
         1013  +      CREATE TABLE tx(y, z);
         1014  +      PRAGMA journal_mode = WAL;
         1015  +    }
         1016  +    db close
         1017  +    list [file exists test.db-wal] [file exists test.db-shm]
         1018  +  } {0 0}
         1019  +  
         1020  +  foreach {tn permissions} {
         1021  +   1 00644
         1022  +   2 00666
         1023  +   3 00600
         1024  +   4 00755
         1025  +  } {
         1026  +    set effective [format %.5o [expr $permissions & ~$umask]]
         1027  +    do_test wal2-12.2.$tn.1 {
         1028  +      file attributes test.db -permissions $permissions
         1029  +      file attributes test.db -permissions
         1030  +    } $permissions
         1031  +    do_test wal2-12.2.$tn.2 {
         1032  +      list [file exists test.db-wal] [file exists test.db-shm]
         1033  +    } {0 0}
         1034  +    do_test wal2-12.2.$tn.3 {
         1035  +      sqlite3 db test.db
         1036  +      execsql { INSERT INTO tx DEFAULT VALUES }
         1037  +      list [file exists test.db-wal] [file exists test.db-shm]
         1038  +    } {1 1}
         1039  +    do_test wal2-12.2.$tn.4 {
         1040  +      list [file attr test.db-wal -perm] [file attr test.db-shm -perm]
         1041  +    } [list $effective $effective]
         1042  +    do_test wal2-12.2.$tn.5 {
         1043  +      db close
         1044  +      list [file exists test.db-wal] [file exists test.db-shm]
         1045  +    } {0 0}
         1046  +  }
         1047  +}
  1000   1048   
  1001   1049   finish_test
  1002   1050