public RC xOpen(string zName, VirtualFile pFile, OPEN flags, out OPEN pOutFlags) { pOutFlags = 0; // If argument zPath is a NULL pointer, this function is required to open a temporary file. Use this buffer to store the file name in. //var zTmpname = new StringBuilder(MAX_PATH + 1); // Buffer used to create temp filename var rc = RC.OK; var eType = (OPEN)((int)flags & 0xFFFFFF00); // Type of file to open var isExclusive = (flags & OPEN.EXCLUSIVE) != 0; var isDelete = (flags & OPEN.DELETEONCLOSE) != 0; var isCreate = (flags & OPEN.CREATE) != 0; var isReadonly = (flags & OPEN.READONLY) != 0; var isReadWrite = (flags & OPEN.READWRITE) != 0; var isOpenJournal = (isCreate && (eType == OPEN.MASTER_JOURNAL || eType == OPEN.MAIN_JOURNAL || eType == OPEN.WAL)); // Check the following statements are true: // (a) Exactly one of the READWRITE and READONLY flags must be set, and // (b) if CREATE is set, then READWRITE must also be set, and // (c) if EXCLUSIVE is set, then CREATE must also be set. // (d) if DELETEONCLOSE is set, then CREATE must also be set. Debug.Assert((!isReadonly || !isReadWrite) && (isReadWrite || isReadonly)); Debug.Assert(!isCreate || isReadWrite); Debug.Assert(!isExclusive || isCreate); Debug.Assert(!isDelete || isCreate); // The main DB, main journal, WAL file and master journal are never automatically deleted. Nor are they ever temporary files. //Debug.Assert((!isDelete && !string.IsNullOrEmpty(zName)) || eType != OPEN.MAIN_DB); Debug.Assert((!isDelete && !string.IsNullOrEmpty(zName)) || eType != OPEN.MAIN_JOURNAL); Debug.Assert((!isDelete && !string.IsNullOrEmpty(zName)) || eType != OPEN.MASTER_JOURNAL); Debug.Assert((!isDelete && !string.IsNullOrEmpty(zName)) || eType != OPEN.WAL); // Assert that the upper layer has set one of the "file-type" flags. Debug.Assert(eType == OPEN.MAIN_DB || eType == OPEN.TEMP_DB || eType == OPEN.MAIN_JOURNAL || eType == OPEN.TEMP_JOURNAL || eType == OPEN.SUBJOURNAL || eType == OPEN.MASTER_JOURNAL || eType == OPEN.TRANSIENT_DB || eType == OPEN.WAL); pFile.S = null; // If the second argument to this function is NULL, generate a temporary file name to use if (string.IsNullOrEmpty(zName)) { Debug.Assert(isDelete && !isOpenJournal); zName = Path.GetRandomFileName(); } // Convert the filename to the system encoding. if (zName.StartsWith("/") && !zName.StartsWith("//")) zName = zName.Substring(1); var dwDesiredAccess = (isReadWrite ? FileAccess.Read | FileAccess.Write : FileAccess.Read); // SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is created. SQLite doesn't use it to indicate "exclusive access" as it is usually understood. FileMode dwCreationDisposition; if (isExclusive) // Creates a new file, only if it does not already exist. */ If the file exists, it fails. dwCreationDisposition = FileMode.CreateNew; else if (isCreate) // Open existing file, or create if it doesn't exist dwCreationDisposition = FileMode.OpenOrCreate; else // Opens a file, only if it exists. dwCreationDisposition = FileMode.Open; var dwShareMode = FileShare.Read | FileShare.Write; #if !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE) FileOptions dwFlagsAndAttributes; #endif if (isDelete) #if !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE) dwFlagsAndAttributes = FileOptions.DeleteOnClose; #endif else #if !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE) dwFlagsAndAttributes = FileOptions.None; #endif // Reports from the internet are that performance is always better if FILE_FLAG_RANDOM_ACCESS is used. FileStream fs = null; if (Environment.OSVersion.Platform >= PlatformID.Win32NT) { // retry opening the file a few times; this is because of a racing condition between a delete and open call to the FS var retries = 3; while (fs == null && retries > 0) try { retries--; #if WINDOWS_PHONE || SQLITE_SILVERLIGHT fs = new IsolatedStorageFileStream(zConverted, dwCreationDisposition, dwDesiredAccess, dwShareMode, IsolatedStorageFile.GetUserStoreForApplication()); #elif !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE) fs = new FileStream(zName, dwCreationDisposition, dwDesiredAccess, dwShareMode, 4096, dwFlagsAndAttributes); #else fs = new FileStream(zName, dwCreationDisposition, dwDesiredAccess, dwShareMode, 4096); #endif #if DEBUG SysEx.OSTRACE("OPEN {0} ({1})", fs.GetHashCode(), fs.Name); #endif } catch (Exception) { Thread.Sleep(100); } } SysEx.OSTRACE("OPEN {0} {1} 0x{2:x} {3}", pFile.GetHashCode(), zName, dwDesiredAccess, fs == null ? "failed" : "ok"); if (fs == null || #if !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE) fs.SafeFileHandle.IsInvalid #else !fs.CanRead #endif ) { #if SQLITE_SILVERLIGHT pFile.lastErrno = 1; #else pFile.LastErrno = (uint)Marshal.GetLastWin32Error(); #endif VirtualFile.winLogError(RC.CANTOPEN, "winOpen", zName); return (isReadWrite ? xOpen(zName, pFile, ((flags | OPEN.READONLY) & ~(OPEN.CREATE | OPEN.READWRITE)), out pOutFlags) : SysEx.SQLITE_CANTOPEN_BKPT()); } pOutFlags = (isReadWrite ? OPEN.READWRITE : OPEN.READONLY); pFile.Clear(); pFile.IsOpen = true; pFile.S = fs; pFile.LastErrno = 0; pFile.Vfs = this; pFile.Shm = null; pFile.Path = zName; pFile.SectorSize = (uint)getSectorSize(zName); return rc; }
private static int FILEHANDLEID(VirtualFile fd) { return fd.GetHashCode(); }