SQLite

Check-in [f71249d3db]
Login

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

Overview
Comment:Simplify the unixFullpathname() function. This adds a dependency on lstat().
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | follow-symlinks
Files: files | file ages | folders
SHA1: f71249d3db9242b8f38955db51a7a5789d002803
User & Date: dan 2016-01-25 18:05:49.964
Context
2016-01-25
18:43
Only use lstat() if the HAVE_LSTAT macro is defined. Fix some test file issues. (check-in: 8a6e4147a6 user: dan tags: follow-symlinks)
18:05
Simplify the unixFullpathname() function. This adds a dependency on lstat(). (check-in: f71249d3db user: dan tags: follow-symlinks)
17:04
Fix issues on unix with opening database files via symlinks that are not in the current working directory. And with nested symlinks. (check-in: 80398fd44f user: dan tags: follow-symlinks)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_unix.c.
476
477
478
479
480
481
482


483
484
485
486
487
488
489
#if defined(HAVE_READLINK)
  { "readlink",     (sqlite3_syscall_ptr)readlink,        0 },
#else
  { "readlink",     (sqlite3_syscall_ptr)0,               0 },
#endif
#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)




}; /* End of the overrideable system calls */


/*
** On some systems, calls to fchown() will trigger a message in a security
** log if they come from non-root processes.  So avoid calling fchown() if







>
>







476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
#if defined(HAVE_READLINK)
  { "readlink",     (sqlite3_syscall_ptr)readlink,        0 },
#else
  { "readlink",     (sqlite3_syscall_ptr)0,               0 },
#endif
#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)

  { "lstat",         (sqlite3_syscall_ptr)lstat,       0  },
#define osLstat      ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)

}; /* End of the overrideable system calls */


/*
** On some systems, calls to fchown() will trigger a message in a security
** log if they come from non-root processes.  So avoid calling fchown() if
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974

5975
5976
5977
5978
5979
5980
5981
5982
5983

5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062

6063
6064
6065



6066













6067



6068

6069
6070
6071

6072
6073


6074
6075
6076
6077
6078
6079
6080
6081
  }else{
    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
  }
  return SQLITE_OK;
}

/*
** Buffer zOut contains a (possibly) relative pathname. Overwrite it with
** the corresponding full pathname.
**
** Parameter nOut is the allocated size of buffer zOut. nByte is the number
** of bytes in the nul-terminated string that it contains (not including
** the nul-terminator itself).
**
** Return SQLITE_OK if successful, or an SQLite error code otherwise.
*/
static int mkFullPathname(
  const char *zPath,              /* Use this path to log any errors */
  char *zOut,                     /* IN/OUT: Buffer to modify */
  int nByte,                      /* size of nul-terminated zOut in bytes */
  int nOut                        /* Allocated size of buffer zOut */
){
  /* If buffer zOut[] now contains an absolute path there is nothing more
  ** to do. If it contains a relative path, do the following:
  **
  **   * move the relative path string so that it is at the end of th
  **     zOut[] buffer.
  **   * Call getcwd() to read the path of the current working directory 
  **     into the start of the zOut[] buffer.
  **   * Append a '/' character to the cwd string and move the 
  **     relative path back within the buffer so that it immediately 
  **     follows the '/'.
  **
  ** This code is written so that if the combination of the CWD and relative
  ** path are larger than the allocated size of zOut[] the CWD is silently
  ** truncated to make it fit. This is Ok, as SQLite refuses to open any
  ** file for which this function returns a full path larger than (nOut-8)
  ** bytes in size.  */
  assert( nByte<nOut );
  testcase( nByte==nOut-5 );
  testcase( nByte==nOut-4 );
  if( zOut[0]!='/' && nByte<nOut-4 ){
    int nCwd;
    int nRem = nOut-nByte-1;
    memmove(&zOut[nRem], zOut, nByte+1);
    zOut[nRem-1] = '\0';

    if( osGetcwd(zOut, nRem-1)==0 ){
      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    }
    nCwd = sqlite3Strlen30(zOut);
    assert( nCwd<=nRem-1 );
    zOut[nCwd] = '/';
    memmove(&zOut[nCwd+1], &zOut[nRem], nByte+1);
  }


  return SQLITE_OK;
}

/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
** zPath. 
**
** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes 
** (in this case, MAX_PATHNAME bytes). The full-path is written to
** this buffer before returning.
*/
static int unixFullPathname(
  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
  const char *zPath,            /* Possibly relative input path */
  int nOut,                     /* Size of output buffer in bytes */
  char *zOut                    /* Output buffer */
){
#if !defined(HAVE_READLINK)
  sqlite3_snprintf(nOut, zOut, "%s", zIn);
  nByte = sqlite3Strlen30(zOut);
  return mkFullPathname(zPath, zOut, sqlite3Strlen30(zOut), nOut);
#else
  int rc = SQLITE_OK;
  int nByte;
  int nLink = 0;                /* Number of symbolic links followed so far */
  int bLink;                    /* True for a symbolic link */
  const char *zIn = zPath;      /* Input path for each iteration of loop */
  char *zDel = 0;

  assert( pVfs->mxPathname==MAX_PATHNAME );
  UNUSED_PARAMETER(pVfs);

  /* It's odd to simulate an io-error here, but really this is just
  ** using the io-error infrastructure to test that SQLite handles this
  ** function failing. This function could fail if, for example, the
  ** current working directory has been unlinked.
  */
  SimulateIOError( return SQLITE_ERROR );

  do {

    /* Attempt to resolve the path as if it were a symbolic link. If it is
    ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if
    ** the identified file is not a symbolic link or does not exist, then
    ** zPath is copied directly into zOut. Either way, nByte is left set to
    ** the size of the string copied into zOut[] in bytes.  */
    assert( (zDel==0 && zIn==zPath) || (zDel!=0 && zIn==zDel) );
    if( zDel ){
      assert( zIn==zDel );
      sqlite3_snprintf(nOut, zDel, "%s", zOut);
    }
    nByte = osReadlink(zIn, zOut, nOut-1);
    if( nByte<0 ){
      if( errno!=EINVAL && errno!=ENOENT ){
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zPath);
      }else{
        sqlite3_snprintf(nOut, zOut, "%s", zIn);
        nByte = sqlite3Strlen30(zOut);
      }
      bLink = 0;
    }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
      sqlite3_log(SQLITE_CANTOPEN, 
          "too many symbolic links (max=%d)", SQLITE_MAX_SYMLINKS
      );
      rc = SQLITE_CANTOPEN_BKPT;
    }else{
      zOut[nByte] = '\0';
      if( zOut[0]!='/' ){
        int n;
        for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
        if( nByte+n+1>nOut ){
          rc = SQLITE_CANTOPEN_BKPT;
        }else{
          memmove(&zOut[n], zOut, nByte+1);
          memcpy(zOut, zIn, n);
          nByte += n;
        }
      }

      if( zDel==0 ){
        zDel = sqlite3_malloc(nOut);
        if( zDel==0 ) rc = SQLITE_NOMEM;



        zIn = (const char*)zDel;













      }



      bLink = 1;

    }

    if( rc==SQLITE_OK ){

      rc = mkFullPathname(zPath, zOut, nByte, nOut);
    }


  }while( bLink && rc==SQLITE_OK );

  sqlite3_free(zDel);
  return rc;
#endif   /* HAVE_READLINK */
}









<
<

<
<
<
<
<


|
|
<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
<
>
|


|
<
|
<

|
>



















<
<
|



|
















|
|
|
|
<
<
|
<
<
<
<
<
|
|
<
<
<

<
<
<
<
<
<

<
<
<
<
<
|
<
<
<
<
|
|
>



>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
>



>
|

>
>
|







5931
5932
5933
5934
5935
5936
5937


5938





5939
5940
5941
5942

5943
5944




















5945
5946


5947
5948
5949
5950
5951

5952

5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974


5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999


6000





6001
6002



6003






6004





6005




6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
  }else{
    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
  }
  return SQLITE_OK;
}

/*


**





*/
static int mkFullPathname(
  const char *zPath,              /* Input path */
  char *zOut,                     /* Output buffer */

  int nOut                        /* Allocated size of buffer zOut */
){




















  int nPath = sqlite3Strlen30(zPath);
  int iOff = 0;


  if( zPath[0]!='/' ){
    if( osGetcwd(zOut, nOut-2)==0 ){
      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    }
    iOff = sqlite3Strlen30(zOut);

    zOut[iOff++] = '/';

  }
  if( (iOff+nPath+1)>nOut ) return SQLITE_CANTOPEN_BKPT;
  sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
  return SQLITE_OK;
}

/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
** zPath. 
**
** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes 
** (in this case, MAX_PATHNAME bytes). The full-path is written to
** this buffer before returning.
*/
static int unixFullPathname(
  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
  const char *zPath,            /* Possibly relative input path */
  int nOut,                     /* Size of output buffer in bytes */
  char *zOut                    /* Output buffer */
){
#if !defined(HAVE_READLINK)


  return mkFullPathname(zPath, zOut, nOut);
#else
  int rc = SQLITE_OK;
  int nByte;
  int nLink = 1;                /* Number of symbolic links followed so far */
  int bLink;                    /* True for a symbolic link */
  const char *zIn = zPath;      /* Input path for each iteration of loop */
  char *zDel = 0;

  assert( pVfs->mxPathname==MAX_PATHNAME );
  UNUSED_PARAMETER(pVfs);

  /* It's odd to simulate an io-error here, but really this is just
  ** using the io-error infrastructure to test that SQLite handles this
  ** function failing. This function could fail if, for example, the
  ** current working directory has been unlinked.
  */
  SimulateIOError( return SQLITE_ERROR );

  do {

    /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
    ** link, or false otherwise.  */
    int bLink = 0;
    struct stat buf;


    if( osLstat(zIn, &buf)!=0 ){





      if( errno!=ENOENT ){
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "stat", zIn);



      }






    }else{





      bLink = S_ISLNK(buf.st_mode);




    }

    if( bLink ){
      if( zDel==0 ){
        zDel = sqlite3_malloc(nOut);
        if( zDel==0 ) rc = SQLITE_NOMEM;
      }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
        rc = SQLITE_CANTOPEN_BKPT;
      }

      if( rc==SQLITE_OK ){
        nByte = osReadlink(zIn, zDel, nOut-1);
        if( nByte<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
        }else if( zDel[0]!='/' ){
          int n;
          for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
          if( nByte+n+1>nOut ){
            rc = SQLITE_CANTOPEN_BKPT;
          }else{
            memmove(&zDel[n], zDel, nByte+1);
            memcpy(zDel, zIn, n);
            nByte += n;
          }
          zDel[nByte] = '\0';
        }
      }

      zIn = zDel;
    }

    if( rc==SQLITE_OK ){
      assert( zIn!=zOut || zIn[0]=='/' );
      rc = mkFullPathname(zIn, zOut, nOut);
    }
    if( bLink==0 ) break;
    zIn = zOut;
  }while( rc==SQLITE_OK );

  sqlite3_free(zDel);
  return rc;
#endif   /* HAVE_READLINK */
}


7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
    UNIXVFS("unix-proxy",    proxyIoFinder ),
#endif
  };
  unsigned int i;          /* Loop counter */

  /* Double-check that the aSyscall[] array has been constructed
  ** correctly.  See ticket [bb3a86e890c8e96ab] */
  assert( ArraySize(aSyscall)==27 );

  /* Register all VFSes defined in the aVfs[] array */
  for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    sqlite3_vfs_register(&aVfs[i], i==0);
  }
  return SQLITE_OK; 
}







|







7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
    UNIXVFS("unix-proxy",    proxyIoFinder ),
#endif
  };
  unsigned int i;          /* Loop counter */

  /* Double-check that the aSyscall[] array has been constructed
  ** correctly.  See ticket [bb3a86e890c8e96ab] */
  assert( ArraySize(aSyscall)==28 );

  /* Register all VFSes defined in the aVfs[] array */
  for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    sqlite3_vfs_register(&aVfs[i], i==0);
  }
  return SQLITE_OK; 
}