/ Check-in [f71249d3]
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 | SQL archive
Timelines: family | ancestors | descendants | both | follow-symlinks
Files: files | file ages | folders
SHA1:f71249d3db9242b8f38955db51a7a5789d002803
User & Date: dan 2016-01-25 18:05:49
Context
2016-01-25
18:43
Only use lstat() if the HAVE_LSTAT macro is defined. Fix some test file issues. check-in: 8a6e4147 user: dan tags: follow-symlinks
18:05
Simplify the unixFullpathname() function. This adds a dependency on lstat(). check-in: f71249d3 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: 80398fd4 user: dan tags: follow-symlinks
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

   476    476   #if defined(HAVE_READLINK)
   477    477     { "readlink",     (sqlite3_syscall_ptr)readlink,        0 },
   478    478   #else
   479    479     { "readlink",     (sqlite3_syscall_ptr)0,               0 },
   480    480   #endif
   481    481   #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
   482    482   
          483  +  { "lstat",         (sqlite3_syscall_ptr)lstat,       0  },
          484  +#define osLstat      ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
   483    485   
   484    486   }; /* End of the overrideable system calls */
   485    487   
   486    488   
   487    489   /*
   488    490   ** On some systems, calls to fchown() will trigger a message in a security
   489    491   ** log if they come from non-root processes.  So avoid calling fchown() if
................................................................................
  5929   5931     }else{
  5930   5932       *pResOut = osAccess(zPath, W_OK|R_OK)==0;
  5931   5933     }
  5932   5934     return SQLITE_OK;
  5933   5935   }
  5934   5936   
  5935   5937   /*
  5936         -** Buffer zOut contains a (possibly) relative pathname. Overwrite it with
  5937         -** the corresponding full pathname.
  5938   5938   **
  5939         -** Parameter nOut is the allocated size of buffer zOut. nByte is the number
  5940         -** of bytes in the nul-terminated string that it contains (not including
  5941         -** the nul-terminator itself).
  5942         -**
  5943         -** Return SQLITE_OK if successful, or an SQLite error code otherwise.
  5944   5939   */
  5945   5940   static int mkFullPathname(
  5946         -  const char *zPath,              /* Use this path to log any errors */
  5947         -  char *zOut,                     /* IN/OUT: Buffer to modify */
  5948         -  int nByte,                      /* size of nul-terminated zOut in bytes */
         5941  +  const char *zPath,              /* Input path */
         5942  +  char *zOut,                     /* Output buffer */
  5949   5943     int nOut                        /* Allocated size of buffer zOut */
  5950   5944   ){
  5951         -  /* If buffer zOut[] now contains an absolute path there is nothing more
  5952         -  ** to do. If it contains a relative path, do the following:
  5953         -  **
  5954         -  **   * move the relative path string so that it is at the end of th
  5955         -  **     zOut[] buffer.
  5956         -  **   * Call getcwd() to read the path of the current working directory 
  5957         -  **     into the start of the zOut[] buffer.
  5958         -  **   * Append a '/' character to the cwd string and move the 
  5959         -  **     relative path back within the buffer so that it immediately 
  5960         -  **     follows the '/'.
  5961         -  **
  5962         -  ** This code is written so that if the combination of the CWD and relative
  5963         -  ** path are larger than the allocated size of zOut[] the CWD is silently
  5964         -  ** truncated to make it fit. This is Ok, as SQLite refuses to open any
  5965         -  ** file for which this function returns a full path larger than (nOut-8)
  5966         -  ** bytes in size.  */
  5967         -  assert( nByte<nOut );
  5968         -  testcase( nByte==nOut-5 );
  5969         -  testcase( nByte==nOut-4 );
  5970         -  if( zOut[0]!='/' && nByte<nOut-4 ){
  5971         -    int nCwd;
  5972         -    int nRem = nOut-nByte-1;
  5973         -    memmove(&zOut[nRem], zOut, nByte+1);
  5974         -    zOut[nRem-1] = '\0';
  5975         -    if( osGetcwd(zOut, nRem-1)==0 ){
         5945  +  int nPath = sqlite3Strlen30(zPath);
         5946  +  int iOff = 0;
         5947  +  if( zPath[0]!='/' ){
         5948  +    if( osGetcwd(zOut, nOut-2)==0 ){
  5976   5949         return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
  5977   5950       }
  5978         -    nCwd = sqlite3Strlen30(zOut);
  5979         -    assert( nCwd<=nRem-1 );
  5980         -    zOut[nCwd] = '/';
  5981         -    memmove(&zOut[nCwd+1], &zOut[nRem], nByte+1);
         5951  +    iOff = sqlite3Strlen30(zOut);
         5952  +    zOut[iOff++] = '/';
  5982   5953     }
  5983         -
         5954  +  if( (iOff+nPath+1)>nOut ) return SQLITE_CANTOPEN_BKPT;
         5955  +  sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
  5984   5956     return SQLITE_OK;
  5985   5957   }
  5986   5958   
  5987   5959   /*
  5988   5960   ** Turn a relative pathname into a full pathname. The relative path
  5989   5961   ** is stored as a nul-terminated string in the buffer pointed to by
  5990   5962   ** zPath. 
................................................................................
  5996   5968   static int unixFullPathname(
  5997   5969     sqlite3_vfs *pVfs,            /* Pointer to vfs object */
  5998   5970     const char *zPath,            /* Possibly relative input path */
  5999   5971     int nOut,                     /* Size of output buffer in bytes */
  6000   5972     char *zOut                    /* Output buffer */
  6001   5973   ){
  6002   5974   #if !defined(HAVE_READLINK)
  6003         -  sqlite3_snprintf(nOut, zOut, "%s", zIn);
  6004         -  nByte = sqlite3Strlen30(zOut);
  6005         -  return mkFullPathname(zPath, zOut, sqlite3Strlen30(zOut), nOut);
         5975  +  return mkFullPathname(zPath, zOut, nOut);
  6006   5976   #else
  6007   5977     int rc = SQLITE_OK;
  6008   5978     int nByte;
  6009         -  int nLink = 0;                /* Number of symbolic links followed so far */
         5979  +  int nLink = 1;                /* Number of symbolic links followed so far */
  6010   5980     int bLink;                    /* True for a symbolic link */
  6011   5981     const char *zIn = zPath;      /* Input path for each iteration of loop */
  6012   5982     char *zDel = 0;
  6013   5983   
  6014   5984     assert( pVfs->mxPathname==MAX_PATHNAME );
  6015   5985     UNUSED_PARAMETER(pVfs);
  6016   5986   
................................................................................
  6019   5989     ** function failing. This function could fail if, for example, the
  6020   5990     ** current working directory has been unlinked.
  6021   5991     */
  6022   5992     SimulateIOError( return SQLITE_ERROR );
  6023   5993   
  6024   5994     do {
  6025   5995   
  6026         -    /* Attempt to resolve the path as if it were a symbolic link. If it is
  6027         -    ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if
  6028         -    ** the identified file is not a symbolic link or does not exist, then
  6029         -    ** zPath is copied directly into zOut. Either way, nByte is left set to
  6030         -    ** the size of the string copied into zOut[] in bytes.  */
  6031         -    assert( (zDel==0 && zIn==zPath) || (zDel!=0 && zIn==zDel) );
  6032         -    if( zDel ){
  6033         -      assert( zIn==zDel );
  6034         -      sqlite3_snprintf(nOut, zDel, "%s", zOut);
  6035         -    }
  6036         -    nByte = osReadlink(zIn, zOut, nOut-1);
  6037         -    if( nByte<0 ){
  6038         -      if( errno!=EINVAL && errno!=ENOENT ){
  6039         -        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zPath);
  6040         -      }else{
  6041         -        sqlite3_snprintf(nOut, zOut, "%s", zIn);
  6042         -        nByte = sqlite3Strlen30(zOut);
         5996  +    /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
         5997  +    ** link, or false otherwise.  */
         5998  +    int bLink = 0;
         5999  +    struct stat buf;
         6000  +    if( osLstat(zIn, &buf)!=0 ){
         6001  +      if( errno!=ENOENT ){
         6002  +        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "stat", zIn);
  6043   6003         }
  6044         -      bLink = 0;
  6045         -    }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
  6046         -      sqlite3_log(SQLITE_CANTOPEN, 
  6047         -          "too many symbolic links (max=%d)", SQLITE_MAX_SYMLINKS
  6048         -      );
  6049         -      rc = SQLITE_CANTOPEN_BKPT;
  6050   6004       }else{
  6051         -      zOut[nByte] = '\0';
  6052         -      if( zOut[0]!='/' ){
  6053         -        int n;
  6054         -        for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
  6055         -        if( nByte+n+1>nOut ){
  6056         -          rc = SQLITE_CANTOPEN_BKPT;
  6057         -        }else{
  6058         -          memmove(&zOut[n], zOut, nByte+1);
  6059         -          memcpy(zOut, zIn, n);
  6060         -          nByte += n;
  6061         -        }
  6062         -      }
         6005  +      bLink = S_ISLNK(buf.st_mode);
         6006  +    }
         6007  +
         6008  +    if( bLink ){
  6063   6009         if( zDel==0 ){
  6064   6010           zDel = sqlite3_malloc(nOut);
  6065   6011           if( zDel==0 ) rc = SQLITE_NOMEM;
  6066         -        zIn = (const char*)zDel;
         6012  +      }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
         6013  +        rc = SQLITE_CANTOPEN_BKPT;
  6067   6014         }
  6068         -      bLink = 1;
         6015  +
         6016  +      if( rc==SQLITE_OK ){
         6017  +        nByte = osReadlink(zIn, zDel, nOut-1);
         6018  +        if( nByte<0 ){
         6019  +          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
         6020  +        }else if( zDel[0]!='/' ){
         6021  +          int n;
         6022  +          for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
         6023  +          if( nByte+n+1>nOut ){
         6024  +            rc = SQLITE_CANTOPEN_BKPT;
         6025  +          }else{
         6026  +            memmove(&zDel[n], zDel, nByte+1);
         6027  +            memcpy(zDel, zIn, n);
         6028  +            nByte += n;
         6029  +          }
         6030  +          zDel[nByte] = '\0';
         6031  +        }
         6032  +      }
         6033  +
         6034  +      zIn = zDel;
  6069   6035       }
  6070   6036   
  6071   6037       if( rc==SQLITE_OK ){
  6072         -      rc = mkFullPathname(zPath, zOut, nByte, nOut);
         6038  +      assert( zIn!=zOut || zIn[0]=='/' );
         6039  +      rc = mkFullPathname(zIn, zOut, nOut);
  6073   6040       }
  6074         -  }while( bLink && rc==SQLITE_OK );
         6041  +    if( bLink==0 ) break;
         6042  +    zIn = zOut;
         6043  +  }while( rc==SQLITE_OK );
  6075   6044   
  6076   6045     sqlite3_free(zDel);
  6077   6046     return rc;
  6078   6047   #endif   /* HAVE_READLINK */
  6079   6048   }
  6080   6049   
  6081   6050   
................................................................................
  7570   7539       UNIXVFS("unix-proxy",    proxyIoFinder ),
  7571   7540   #endif
  7572   7541     };
  7573   7542     unsigned int i;          /* Loop counter */
  7574   7543   
  7575   7544     /* Double-check that the aSyscall[] array has been constructed
  7576   7545     ** correctly.  See ticket [bb3a86e890c8e96ab] */
  7577         -  assert( ArraySize(aSyscall)==27 );
         7546  +  assert( ArraySize(aSyscall)==28 );
  7578   7547   
  7579   7548     /* Register all VFSes defined in the aVfs[] array */
  7580   7549     for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
  7581   7550       sqlite3_vfs_register(&aVfs[i], i==0);
  7582   7551     }
  7583   7552     return SQLITE_OK; 
  7584   7553   }