⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os.c

📁 SQLite 2.8.6 源代码,用来在Linux/Unix/Windows上编译安装.它是一个小型的数据库,但是非常好用,速度也快,一般的数据库查询之类的操作据统计比MySQL,PostgreSQL
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** 2001 September 16**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.************************************************************************************ This file contains code that is specific to particular operating** systems.  The purpose of this file is to provide a uniform abstraction** on which the rest of SQLite can operate.*/#include "os.h"          /* Must be first to enable large file support */#include "sqliteInt.h"#if OS_UNIX# include <time.h># include <errno.h># include <unistd.h># ifndef O_LARGEFILE#  define O_LARGEFILE 0# endif# ifdef SQLITE_DISABLE_LFS#  undef O_LARGEFILE#  define O_LARGEFILE 0# endif# ifndef O_NOFOLLOW#  define O_NOFOLLOW 0# endif# ifndef O_BINARY#  define O_BINARY 0# endif#endif#if OS_WIN# include <winbase.h>#endif#if OS_MAC# include <extras.h># include <path2fss.h># include <TextUtils.h># include <FinderRegistry.h># include <Folders.h># include <Timer.h># include <OSUtils.h>#endif/*** The DJGPP compiler environment looks mostly like Unix, but it** lacks the fcntl() system call.  So redefine fcntl() to be something** that always succeeds.  This means that locking does not occur under** DJGPP.  But its DOS - what did you expect?*/#ifdef __DJGPP__# define fcntl(A,B,C) 0#endif/*** Macros for performance tracing.  Normally turned off*/#if 0static int last_page = 0;__inline__ unsigned long long int hwtime(void){  unsigned long long int x;  __asm__("rdtsc\n\t"          "mov %%edx, %%ecx\n\t"          :"=A" (x));  return x;}static unsigned long long int g_start;static unsigned int elapse;#define TIMER_START       g_start=hwtime()#define TIMER_END         elapse=hwtime()-g_start#define SEEK(X)           last_page=(X)#define TRACE1(X)         fprintf(stderr,X)#define TRACE2(X,Y)       fprintf(stderr,X,Y)#define TRACE3(X,Y,Z)     fprintf(stderr,X,Y,Z)#define TRACE4(X,Y,Z,A)   fprintf(stderr,X,Y,Z,A)#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B)#else#define TIMER_START#define TIMER_END#define SEEK(X)#define TRACE1(X)#define TRACE2(X,Y)#define TRACE3(X,Y,Z)#define TRACE4(X,Y,Z,A)#define TRACE5(X,Y,Z,A,B)#endif#if OS_UNIX/*** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)** section 6.5.2.2 lines 483 through 490 specify that when a process** sets or clears a lock, that operation overrides any prior locks set** by the same process.  It does not explicitly say so, but this implies** that it overrides locks set by the same process using a different** file descriptor.  Consider this test case:****       int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);**       int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);**** Suppose ./file1 and ./file2 are really the same file (because** one is a hard or symbolic link to the other) then if you set** an exclusive lock on fd1, then try to get an exclusive lock** on fd2, it works.  I would have expected the second lock to** fail since there was already a lock on the file due to fd1.** But not so.  Since both locks came from the same process, the** second overrides the first, even though they were on different** file descriptors opened on different file names.**** Bummer.  If you ask me, this is broken.  Badly broken.  It means** that we cannot use POSIX locks to synchronize file access among** competing threads of the same process.  POSIX locks will work fine** to synchronize access for threads in separate processes, but not** threads within the same process.**** To work around the problem, SQLite has to manage file locks internally** on its own.  Whenever a new database is opened, we have to find the** specific inode of the database file (the inode is determined by the** st_dev and st_ino fields of the stat structure that fstat() fills in)** and check for locks already existing on that inode.  When locks are** created or removed, we have to look at our own internal record of the** locks to see if another thread has previously set a lock on that same** inode.**** The OsFile structure for POSIX is no longer just an integer file** descriptor.  It is now a structure that holds the integer file** descriptor and a pointer to a structure that describes the internal** locks on the corresponding inode.  There is one locking structure** per inode, so if the same inode is opened twice, both OsFile structures** point to the same locking structure.  The locking structure keeps** a reference count (so we will know when to delete it) and a "cnt"** field that tells us its internal lock status.  cnt==0 means the** file is unlocked.  cnt==-1 means the file has an exclusive lock.** cnt>0 means there are cnt shared locks on the file.**** Any attempt to lock or unlock a file first checks the locking** structure.  The fcntl() system call is only invoked to set a ** POSIX lock if the internal lock structure transitions between** a locked and an unlocked state.*//*** An instance of the following structure serves as the key used** to locate a particular lockInfo structure given its inode. */struct inodeKey {  dev_t dev;   /* Device number */  ino_t ino;   /* Inode number */};/*** An instance of the following structure is allocated for each inode.** A single inode can have multiple file descriptors, so each OsFile** structure contains a pointer to an instance of this object and this** object keeps a count of the number of OsFiles pointing to it.*/struct lockInfo {  struct inodeKey key;  /* The lookup key */  int cnt;              /* 0: unlocked.  -1: write lock.  1...: read lock. */  int nRef;             /* Number of pointers to this structure */};/* ** This hash table maps inodes (in the form of inodeKey structures) into** pointers to lockInfo structures.*/static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };/*** Given a file descriptor, locate a lockInfo structure that describes** that file descriptor.  Create a new one if necessary.  NULL might** be returned if malloc() fails.*/static struct lockInfo *findLockInfo(int fd){  int rc;  struct inodeKey key;  struct stat statbuf;  struct lockInfo *pInfo;  rc = fstat(fd, &statbuf);  if( rc!=0 ) return 0;  memset(&key, 0, sizeof(key));  key.dev = statbuf.st_dev;  key.ino = statbuf.st_ino;  pInfo = (struct lockInfo*)sqliteHashFind(&lockHash, &key, sizeof(key));  if( pInfo==0 ){    struct lockInfo *pOld;    pInfo = sqliteMalloc( sizeof(*pInfo) );    if( pInfo==0 ) return 0;    pInfo->key = key;    pInfo->nRef = 1;    pInfo->cnt = 0;    pOld = sqliteHashInsert(&lockHash, &pInfo->key, sizeof(key), pInfo);    if( pOld!=0 ){      assert( pOld==pInfo );      sqliteFree(pInfo);      pInfo = 0;    }  }else{    pInfo->nRef++;  }  return pInfo;}/*** Release a lockInfo structure previously allocated by findLockInfo().*/static void releaseLockInfo(struct lockInfo *pInfo){  pInfo->nRef--;  if( pInfo->nRef==0 ){    sqliteHashInsert(&lockHash, &pInfo->key, sizeof(pInfo->key), 0);    sqliteFree(pInfo);  }}#endif  /** POSIX advisory lock work-around **//*** If we compile with the SQLITE_TEST macro set, then the following block** of code will give us the ability to simulate a disk I/O error.  This** is used for testing the I/O recovery logic.*/#ifdef SQLITE_TESTint sqlite_io_error_pending = 0;#define SimulateIOError(A)  \   if( sqlite_io_error_pending ) \     if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; }static void local_ioerr(){  sqlite_io_error_pending = 0;  /* Really just a place to set a breakpoint */}#else#define SimulateIOError(A)#endif/*** When testing, keep a count of the number of open files.*/#ifdef SQLITE_TESTint sqlite_open_file_count = 0;#define OpenCounter(X)  sqlite_open_file_count+=(X)#else#define OpenCounter(X)#endif/*** Delete the named file*/int sqliteOsDelete(const char *zFilename){#if OS_UNIX  unlink(zFilename);#endif#if OS_WIN  DeleteFile(zFilename);#endif#if OS_MAC  unlink(zFilename);#endif  return SQLITE_OK;}/*** Return TRUE if the named file exists.*/int sqliteOsFileExists(const char *zFilename){#if OS_UNIX  return access(zFilename, 0)==0;#endif#if OS_WIN  return GetFileAttributes(zFilename) != 0xffffffff;#endif#if OS_MAC  return access(zFilename, 0)==0;#endif}#if 0 /* NOT USED *//*** Change the name of an existing file.*/int sqliteOsFileRename(const char *zOldName, const char *zNewName){#if OS_UNIX  if( link(zOldName, zNewName) ){    return SQLITE_ERROR;  }  unlink(zOldName);  return SQLITE_OK;#endif#if OS_WIN  if( !MoveFile(zOldName, zNewName) ){    return SQLITE_ERROR;  }  return SQLITE_OK;#endif#if OS_MAC  /**** FIX ME ***/  return SQLITE_ERROR;#endif}#endif /* NOT USED *//*** Attempt to open a file for both reading and writing.  If that** fails, try opening it read-only.  If the file does not exist,** try to create it.**** On success, a handle for the open file is written to *id** and *pReadonly is set to 0 if the file was opened for reading and** writing or 1 if the file was opened read-only.  The function returns** SQLITE_OK.**** On failure, the function returns SQLITE_CANTOPEN and leaves** *id and *pReadonly unchanged.*/int sqliteOsOpenReadWrite(  const char *zFilename,  OsFile *id,  int *pReadonly){#if OS_UNIX  id->dirfd = -1;  id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);  if( id->fd<0 ){    id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);    if( id->fd<0 ){      return SQLITE_CANTOPEN;     }    *pReadonly = 1;  }else{    *pReadonly = 0;  }  sqliteOsEnterMutex();  id->pLock = findLockInfo(id->fd);  sqliteOsLeaveMutex();  if( id->pLock==0 ){    close(id->fd);    return SQLITE_NOMEM;  }  id->locked = 0;  TRACE3("OPEN    %-3d %s\n", id->fd, zFilename);  OpenCounter(+1);  return SQLITE_OK;#endif#if OS_WIN  HANDLE h = CreateFile(zFilename,     GENERIC_READ | GENERIC_WRITE,     FILE_SHARE_READ | FILE_SHARE_WRITE,     NULL,     OPEN_ALWAYS,     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,     NULL  );  if( h==INVALID_HANDLE_VALUE ){    h = CreateFile(zFilename,       GENERIC_READ,       FILE_SHARE_READ,       NULL,       OPEN_ALWAYS,       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,       NULL    );    if( h==INVALID_HANDLE_VALUE ){      return SQLITE_CANTOPEN;    }    *pReadonly = 1;  }else{    *pReadonly = 0;  }  id->h = h;  id->locked = 0;  OpenCounter(+1);  return SQLITE_OK;#endif#if OS_MAC  FSSpec fsSpec;# ifdef _LARGE_FILE  HFSUniStr255 dfName;  FSRef fsRef;  if( __path2fss(zFilename, &fsSpec) != noErr ){    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )      return SQLITE_CANTOPEN;  }  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )    return SQLITE_CANTOPEN;  FSGetDataForkName(&dfName);  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,                 fsRdWrShPerm, &(id->refNum)) != noErr ){    if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,                   fsRdWrPerm, &(id->refNum)) != noErr ){      if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,                   fsRdPerm, &(id->refNum)) != noErr )        return SQLITE_CANTOPEN;      else        *pReadonly = 1;    } else      *pReadonly = 0;  } else    *pReadonly = 0;# else  __path2fss(zFilename, &fsSpec);  if( !sqliteOsFileExists(zFilename) ){    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )      return SQLITE_CANTOPEN;  }  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){    if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){      if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )        return SQLITE_CANTOPEN;      else        *pReadonly = 1;    } else      *pReadonly = 0;  } else    *pReadonly = 0;# endif  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){    id->refNumRF = -1;  }  id->locked = 0;  id->delOnClose = 0;  OpenCounter(+1);  return SQLITE_OK;#endif}/*** Attempt to open a new file for exclusive access by this process.** The file will be opened for both reading and writing.  To avoid** a potential security problem, we do not allow the file to have** previously existed.  Nor do we allow the file to be a symbolic** link.**** If delFlag is true, then make arrangements to automatically delete** the file when it is closed.**** On success, write the file handle into *id and return SQLITE_OK.**** On failure, return SQLITE_CANTOPEN.*/int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){#if OS_UNIX  if( access(zFilename, 0)==0 ){    return SQLITE_CANTOPEN;  }  id->dirfd = -1;  id->fd = open(zFilename,                O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);  if( id->fd<0 ){    return SQLITE_CANTOPEN;  }  sqliteOsEnterMutex();  id->pLock = findLockInfo(id->fd);  sqliteOsLeaveMutex();  if( id->pLock==0 ){    close(id->fd);    unlink(zFilename);    return SQLITE_NOMEM;  }  id->locked = 0;  if( delFlag ){    unlink(zFilename);  }  TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename);  OpenCounter(+1);  return SQLITE_OK;#endif#if OS_WIN  HANDLE h;  int fileflags;  if( delFlag ){    fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS                      | FILE_FLAG_DELETE_ON_CLOSE;  }else{    fileflags = FILE_FLAG_RANDOM_ACCESS;  }  h = CreateFile(zFilename,     GENERIC_READ | GENERIC_WRITE,     0,     NULL,     CREATE_ALWAYS,     fileflags,     NULL  );  if( h==INVALID_HANDLE_VALUE ){    return SQLITE_CANTOPEN;  }  id->h = h;  id->locked = 0;  OpenCounter(+1);  return SQLITE_OK;#endif#if OS_MAC  FSSpec fsSpec;# ifdef _LARGE_FILE  HFSUniStr255 dfName;  FSRef fsRef;  __path2fss(zFilename, &fsSpec);  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )    return SQLITE_CANTOPEN;  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )    return SQLITE_CANTOPEN;  FSGetDataForkName(&dfName);  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,                 fsRdWrPerm, &(id->refNum)) != noErr )    return SQLITE_CANTOPEN;# else  __path2fss(zFilename, &fsSpec);  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )    return SQLITE_CANTOPEN;  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )    return SQLITE_CANTOPEN;# endif  id->refNumRF = -1;  id->locked = 0;  id->delOnClose = delFlag;  if (delFlag)    id->pathToDel = sqliteOsFullPathname(zFilename);  OpenCounter(+1);  return SQLITE_OK;#endif}/*** Attempt to open a new file for read-only access.**** On success, write the file handle into *id and return SQLITE_OK.**** On failure, return SQLITE_CANTOPEN.*/int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){#if OS_UNIX  id->dirfd = -1;  id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);  if( id->fd<0 ){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -