Index: mozilla/security/nss/lib/softoken/sdb.c |
=================================================================== |
--- mozilla/security/nss/lib/softoken/sdb.c (revision 180567) |
+++ mozilla/security/nss/lib/softoken/sdb.c (working copy) |
@@ -24,14 +24,18 @@ |
#include <sqlite3.h> |
#include "prthread.h" |
#include "prio.h" |
-#include "stdio.h" |
+#include <stdio.h> |
#include "secport.h" |
#include "prmon.h" |
#include "prenv.h" |
+#include "prprf.h" |
#include "prsystem.h" /* for PR_GetDirectorySeparator() */ |
-#include "sys/stat.h" |
-#if defined (_WIN32) |
+#include <sys/stat.h> |
+#if defined(_WIN32) |
#include <io.h> |
+#include <windows.h> |
+#elif defined(XP_UNIX) |
+#include <unistd.h> |
#endif |
#ifdef SQLITE_UNSAFE_THREADS |
@@ -187,107 +191,117 @@ |
} |
/* |
- * |
- * strdup limited to 'n' bytes. (Note: len of file is assumed to be >= len) |
- * |
- * We don't have a PORT_ version of this function, |
- * I suspect it's only normally available in glib, |
+ * find out where sqlite stores the temp tables. We do this by replicating |
+ * the logic from sqlite. |
*/ |
+#if defined(_WIN32) |
static char * |
-sdb_strndup(const char *file, int len) |
+sdb_getFallbackTempDir(void) |
{ |
- char *result = PORT_Alloc(len+1); |
+ /* sqlite uses sqlite3_temp_directory if it is not NULL. We don't have |
+ * access to sqlite3_temp_directory because it is not exported from |
+ * sqlite3.dll. Assume sqlite3_win32_set_directory isn't called and |
+ * sqlite3_temp_directory is NULL. |
+ */ |
+ char path[MAX_PATH]; |
+ DWORD rv; |
+ size_t len; |
- if (result == NULL) { |
- return result; |
- } |
- |
- PORT_Memcpy(result, file, len); |
- result[len] = 0; |
- return result; |
+ rv = GetTempPathA(MAX_PATH, path); |
+ if (rv > MAX_PATH || rv == 0) |
+ return NULL; |
+ len = strlen(path); |
+ if (len == 0) |
+ return NULL; |
+ /* The returned string ends with a backslash, for example, "C:\TEMP\". */ |
+ if (path[len - 1] == '\\') |
+ path[len - 1] = '\0'; |
+ return PORT_Strdup(path); |
} |
- |
-/* |
- * call back from sqlite3_exec("Pragma database_list"). Looks for the |
- * temp directory, then return the file the temp directory is stored |
- * at. */ |
-static int |
-sdb_getTempDirCallback(void *arg, int columnCount, char **cval, char **cname) |
+#elif defined(XP_UNIX) |
+static char * |
+sdb_getFallbackTempDir(void) |
{ |
- int i; |
- int found = 0; |
- char *file = NULL; |
- char *end, *dir; |
- char dirsep; |
+ const char *azDirs[] = { |
+ NULL, |
+ NULL, |
+ "/var/tmp", |
+ "/usr/tmp", |
+ "/tmp", |
+ NULL /* List terminator */ |
+ }; |
+ unsigned int i; |
+ struct stat buf; |
+ const char *zDir = NULL; |
- /* we've already found the temp directory, don't look at any more records*/ |
- if (*(char **)arg) { |
- return SQLITE_OK; |
- } |
+ azDirs[0] = sqlite3_temp_directory; |
+ azDirs[1] = getenv("TMPDIR"); |
- /* look at the columns to see if this record is the temp database, |
- * and does it say where it is stored */ |
- for (i=0; i < columnCount; i++) { |
- if (PORT_Strcmp(cname[i],"name") == 0) { |
- if (PORT_Strcmp(cval[i], "temp") == 0) { |
- found++; |
- continue; |
- } |
- } |
- if (PORT_Strcmp(cname[i],"file") == 0) { |
- if (cval[i] && (*cval[i] != 0)) { |
- file = cval[i]; |
- } |
- } |
+ for (i = 0; i < PR_ARRAY_SIZE(azDirs); i++) { |
+ zDir = azDirs[i]; |
+ if (zDir == NULL) continue; |
+ if (stat(zDir, &buf)) continue; |
+ if (!S_ISDIR(buf.st_mode)) continue; |
+ if (access(zDir, 07)) continue; |
+ break; |
} |
- /* if we couldn't find it, ask for the next record */ |
- if (!found || !file) { |
- return SQLITE_OK; |
- } |
+ if (zDir == NULL) |
+ return NULL; |
+ return PORT_Strdup(zDir); |
+} |
+#else |
+#error "sdb_getFallbackTempDir not implemented" |
+#endif |
- /* drop of the database file name and just return the directory */ |
- dirsep = PR_GetDirectorySeparator(); |
- end = PORT_Strrchr(file, dirsep); |
- if (!end) { |
- return SQLITE_OK; |
- } |
- dir = sdb_strndup(file, end-file); |
+#ifndef SQLITE_FCNTL_TEMPFILENAME |
+/* SQLITE_FCNTL_TEMPFILENAME was added in SQLite 3.7.15 */ |
+#define SQLITE_FCNTL_TEMPFILENAME 16 |
+#endif |
- *(char **)arg = dir; |
- return SQLITE_OK; |
-} |
- |
-/* |
- * find out where sqlite stores the temp tables. We do this by creating |
- * a temp table, then looking for the database name that sqlite3 creates. |
- */ |
static char * |
sdb_getTempDir(sqlite3 *sqlDB) |
{ |
- char *tempDir = NULL; |
- int sqlerr; |
+ int sqlrv; |
+ char *result = NULL; |
+ char *tempName = NULL; |
+ char *foundSeparator = NULL; |
- /* create a temporary table */ |
- sqlerr = sqlite3_exec(sqlDB, "CREATE TEMPORARY TABLE myTemp (id)", |
- NULL, 0, NULL); |
- if (sqlerr != SQLITE_OK) { |
+ /* Obtain temporary filename in sqlite's directory for temporary tables */ |
+ sqlrv = sqlite3_file_control(sqlDB, 0, SQLITE_FCNTL_TEMPFILENAME, |
+ (void*)&tempName); |
+ if (sqlrv == SQLITE_NOTFOUND) { |
+ /* SQLITE_FCNTL_TEMPFILENAME not implemented because we are using |
+ * an older SQLite. */ |
+ return sdb_getFallbackTempDir(); |
+ } |
+ if (sqlrv != SQLITE_OK) { |
return NULL; |
} |
- /* look for through the database list for the temp directory */ |
- sqlerr = sqlite3_exec(sqlDB, "PRAGMA database_list", |
- sdb_getTempDirCallback, &tempDir, NULL); |
- /* drop the temp table we created */ |
- sqlite3_exec(sqlDB, "DROP TABLE myTemp", NULL, 0, NULL); |
+ /* We'll extract the temporary directory from tempName */ |
+ foundSeparator = PORT_Strrchr(tempName, PR_GetDirectorySeparator()); |
+ if (foundSeparator) { |
+ /* We shorten the temp filename string to contain only |
+ * the directory name (including the trailing separator). |
+ * We know the byte after the foundSeparator position is |
+ * safe to use, in the shortest scenario it contains the |
+ * end-of-string byte. |
+ * By keeping the separator at the found position, it will |
+ * even work if tempDir consists of the separator, only. |
+ * (In this case the toplevel directory will be used for |
+ * access speed testing). */ |
+ ++foundSeparator; |
+ *foundSeparator = 0; |
- if (sqlerr != SQLITE_OK) { |
- return NULL; |
+ /* Now we copy the directory name for our caller */ |
+ result = PORT_Strdup(tempName); |
} |
- return tempDir; |
+ |
+ sqlite3_free(tempName); |
+ return result; |
} |
- |
/* |
* Map SQL_LITE errors to PKCS #11 errors as best we can. |
*/ |
@@ -326,11 +340,13 @@ |
*/ |
static char *sdb_BuildFileName(const char * directory, |
const char *prefix, const char *type, |
- int version, int flags) |
+ int version) |
{ |
char *dbname = NULL; |
/* build the full dbname */ |
- dbname = sqlite3_mprintf("%s/%s%s%d.db",directory, prefix, type, version); |
+ dbname = sqlite3_mprintf("%s%c%s%s%d.db", directory, |
+ (int)(unsigned char)PR_GetDirectorySeparator(), |
+ prefix, type, version); |
return dbname; |
} |
@@ -346,29 +362,64 @@ |
PRIntervalTime time; |
PRIntervalTime delta; |
PRIntervalTime duration = PR_MillisecondsToInterval(33); |
+ const char *doesntExistName = "_dOeSnotExist_.db"; |
+ char *temp, *tempStartOfFilename; |
+ size_t maxTempLen, maxFileNameLen, directoryLength; |
/* no directory, just return one */ |
if (directory == NULL) { |
return 1; |
} |
+ /* our calculation assumes time is a 4 bytes == 32 bit integer */ |
+ PORT_Assert(sizeof(time) == 4); |
+ |
+ directoryLength = strlen(directory); |
+ |
+ maxTempLen = directoryLength + strlen(doesntExistName) |
+ + 1 /* potential additional separator char */ |
+ + 11 /* max chars for 32 bit int plus potential sign */ |
+ + 1; /* zero terminator */ |
+ |
+ temp = PORT_Alloc(maxTempLen); |
+ if (!temp) { |
+ return 1; |
+ } |
+ |
+ /* We'll copy directory into temp just once, then ensure it ends |
+ * with the directory separator, then remember the position after |
+ * the separator, and calculate the number of remaining bytes. */ |
+ |
+ strcpy(temp, directory); |
+ if (directory[directoryLength - 1] != PR_GetDirectorySeparator()) { |
+ temp[directoryLength++] = PR_GetDirectorySeparator(); |
+ } |
+ tempStartOfFilename = temp + directoryLength; |
+ maxFileNameLen = maxTempLen - directoryLength; |
+ |
/* measure number of Access operations that can be done in 33 milliseconds |
* (1/30'th of a second), or 10000 operations, which ever comes first. |
*/ |
time = PR_IntervalNow(); |
for (i=0; i < 10000u; i++) { |
- char *temp; |
PRIntervalTime next; |
- temp = sdb_BuildFileName(directory,"","._dOeSnotExist_", time+i, 0); |
+ /* We'll use the variable part first in the filename string, just in |
+ * case it's longer than assumed, so if anything gets cut off, it |
+ * will be cut off from the constant part. |
+ * This code assumes the directory name at the beginning of |
+ * temp remains unchanged during our loop. */ |
+ PR_snprintf(tempStartOfFilename, maxFileNameLen, |
+ ".%lu%s", (PRUint32)(time+i), doesntExistName); |
PR_Access(temp,PR_ACCESS_EXISTS); |
- sqlite3_free(temp); |
next = PR_IntervalNow(); |
delta = next - time; |
if (delta >= duration) |
break; |
} |
+ PORT_Free(temp); |
+ |
/* always return 1 or greater */ |
return i ? i : 1u; |
} |
@@ -1936,9 +1987,9 @@ |
SDB **certdb, SDB **keydb, int *newInit) |
{ |
char *cert = sdb_BuildFileName(directory, certPrefix, |
- "cert", cert_version, flags); |
+ "cert", cert_version); |
char *key = sdb_BuildFileName(directory, keyPrefix, |
- "key", key_version, flags); |
+ "key", key_version); |
CK_RV error = CKR_OK; |
int inUpdate; |
PRUint32 accessOps; |