line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
** 2001 September 16 |
3
|
|
|
|
|
|
|
** |
4
|
|
|
|
|
|
|
** The author disclaims copyright to this source code. In place of |
5
|
|
|
|
|
|
|
** a legal notice, here is a blessing: |
6
|
|
|
|
|
|
|
** |
7
|
|
|
|
|
|
|
** May you do good and not evil. |
8
|
|
|
|
|
|
|
** May you find forgiveness for yourself and forgive others. |
9
|
|
|
|
|
|
|
** May you share freely, never taking more than you give. |
10
|
|
|
|
|
|
|
** |
11
|
|
|
|
|
|
|
****************************************************************************** |
12
|
|
|
|
|
|
|
** |
13
|
|
|
|
|
|
|
** This file contains code that is specific to particular operating |
14
|
|
|
|
|
|
|
** systems. The purpose of this file is to provide a uniform abstraction |
15
|
|
|
|
|
|
|
** on which the rest of SQLite can operate. |
16
|
|
|
|
|
|
|
*/ |
17
|
|
|
|
|
|
|
#include "os.h" /* Must be first to enable large file support */ |
18
|
|
|
|
|
|
|
#include "sqliteInt.h" |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
#if OS_UNIX |
21
|
|
|
|
|
|
|
# include |
22
|
|
|
|
|
|
|
# include |
23
|
|
|
|
|
|
|
# include |
24
|
|
|
|
|
|
|
# ifndef O_LARGEFILE |
25
|
|
|
|
|
|
|
# define O_LARGEFILE 0 |
26
|
|
|
|
|
|
|
# endif |
27
|
|
|
|
|
|
|
# ifdef SQLITE_DISABLE_LFS |
28
|
|
|
|
|
|
|
# undef O_LARGEFILE |
29
|
|
|
|
|
|
|
# define O_LARGEFILE 0 |
30
|
|
|
|
|
|
|
# endif |
31
|
|
|
|
|
|
|
# ifndef O_NOFOLLOW |
32
|
|
|
|
|
|
|
# define O_NOFOLLOW 0 |
33
|
|
|
|
|
|
|
# endif |
34
|
|
|
|
|
|
|
# ifndef O_BINARY |
35
|
|
|
|
|
|
|
# define O_BINARY 0 |
36
|
|
|
|
|
|
|
# endif |
37
|
|
|
|
|
|
|
#endif |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
#if OS_WIN |
41
|
|
|
|
|
|
|
# include |
42
|
|
|
|
|
|
|
#endif |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
#if OS_MAC |
45
|
|
|
|
|
|
|
# include |
46
|
|
|
|
|
|
|
# include |
47
|
|
|
|
|
|
|
# include |
48
|
|
|
|
|
|
|
# include |
49
|
|
|
|
|
|
|
# include |
50
|
|
|
|
|
|
|
# include |
51
|
|
|
|
|
|
|
# include |
52
|
|
|
|
|
|
|
#endif |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
/* |
55
|
|
|
|
|
|
|
** The DJGPP compiler environment looks mostly like Unix, but it |
56
|
|
|
|
|
|
|
** lacks the fcntl() system call. So redefine fcntl() to be something |
57
|
|
|
|
|
|
|
** that always succeeds. This means that locking does not occur under |
58
|
|
|
|
|
|
|
** DJGPP. But its DOS - what did you expect? |
59
|
|
|
|
|
|
|
*/ |
60
|
|
|
|
|
|
|
#ifdef __DJGPP__ |
61
|
|
|
|
|
|
|
# define fcntl(A,B,C) 0 |
62
|
|
|
|
|
|
|
#endif |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
/* |
65
|
|
|
|
|
|
|
** Macros used to determine whether or not to use threads. The |
66
|
|
|
|
|
|
|
** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for |
67
|
|
|
|
|
|
|
** Posix threads and SQLITE_W32_THREADS is defined if we are |
68
|
|
|
|
|
|
|
** synchronizing using Win32 threads. |
69
|
|
|
|
|
|
|
*/ |
70
|
|
|
|
|
|
|
#if OS_UNIX && defined(THREADSAFE) && THREADSAFE |
71
|
|
|
|
|
|
|
# include |
72
|
|
|
|
|
|
|
# define SQLITE_UNIX_THREADS 1 |
73
|
|
|
|
|
|
|
#endif |
74
|
|
|
|
|
|
|
#if OS_WIN && defined(THREADSAFE) && THREADSAFE |
75
|
|
|
|
|
|
|
# define SQLITE_W32_THREADS 1 |
76
|
|
|
|
|
|
|
#endif |
77
|
|
|
|
|
|
|
#if OS_MAC && defined(THREADSAFE) && THREADSAFE |
78
|
|
|
|
|
|
|
# include |
79
|
|
|
|
|
|
|
# define SQLITE_MACOS_MULTITASKING 1 |
80
|
|
|
|
|
|
|
#endif |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
/* |
83
|
|
|
|
|
|
|
** Macros for performance tracing. Normally turned off |
84
|
|
|
|
|
|
|
*/ |
85
|
|
|
|
|
|
|
#if 0 |
86
|
|
|
|
|
|
|
static int last_page = 0; |
87
|
|
|
|
|
|
|
__inline__ unsigned long long int hwtime(void){ |
88
|
|
|
|
|
|
|
unsigned long long int x; |
89
|
|
|
|
|
|
|
__asm__("rdtsc\n\t" |
90
|
|
|
|
|
|
|
"mov %%edx, %%ecx\n\t" |
91
|
|
|
|
|
|
|
:"=A" (x)); |
92
|
|
|
|
|
|
|
return x; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
static unsigned long long int g_start; |
95
|
|
|
|
|
|
|
static unsigned int elapse; |
96
|
|
|
|
|
|
|
#define TIMER_START g_start=hwtime() |
97
|
|
|
|
|
|
|
#define TIMER_END elapse=hwtime()-g_start |
98
|
|
|
|
|
|
|
#define SEEK(X) last_page=(X) |
99
|
|
|
|
|
|
|
#define TRACE1(X) fprintf(stderr,X) |
100
|
|
|
|
|
|
|
#define TRACE2(X,Y) fprintf(stderr,X,Y) |
101
|
|
|
|
|
|
|
#define TRACE3(X,Y,Z) fprintf(stderr,X,Y,Z) |
102
|
|
|
|
|
|
|
#define TRACE4(X,Y,Z,A) fprintf(stderr,X,Y,Z,A) |
103
|
|
|
|
|
|
|
#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B) |
104
|
|
|
|
|
|
|
#else |
105
|
|
|
|
|
|
|
#define TIMER_START |
106
|
|
|
|
|
|
|
#define TIMER_END |
107
|
|
|
|
|
|
|
#define SEEK(X) |
108
|
|
|
|
|
|
|
#define TRACE1(X) |
109
|
|
|
|
|
|
|
#define TRACE2(X,Y) |
110
|
|
|
|
|
|
|
#define TRACE3(X,Y,Z) |
111
|
|
|
|
|
|
|
#define TRACE4(X,Y,Z,A) |
112
|
|
|
|
|
|
|
#define TRACE5(X,Y,Z,A,B) |
113
|
|
|
|
|
|
|
#endif |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
#if OS_UNIX |
117
|
|
|
|
|
|
|
/* |
118
|
|
|
|
|
|
|
** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996) |
119
|
|
|
|
|
|
|
** section 6.5.2.2 lines 483 through 490 specify that when a process |
120
|
|
|
|
|
|
|
** sets or clears a lock, that operation overrides any prior locks set |
121
|
|
|
|
|
|
|
** by the same process. It does not explicitly say so, but this implies |
122
|
|
|
|
|
|
|
** that it overrides locks set by the same process using a different |
123
|
|
|
|
|
|
|
** file descriptor. Consider this test case: |
124
|
|
|
|
|
|
|
** |
125
|
|
|
|
|
|
|
** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); |
126
|
|
|
|
|
|
|
** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); |
127
|
|
|
|
|
|
|
** |
128
|
|
|
|
|
|
|
** Suppose ./file1 and ./file2 are really the same file (because |
129
|
|
|
|
|
|
|
** one is a hard or symbolic link to the other) then if you set |
130
|
|
|
|
|
|
|
** an exclusive lock on fd1, then try to get an exclusive lock |
131
|
|
|
|
|
|
|
** on fd2, it works. I would have expected the second lock to |
132
|
|
|
|
|
|
|
** fail since there was already a lock on the file due to fd1. |
133
|
|
|
|
|
|
|
** But not so. Since both locks came from the same process, the |
134
|
|
|
|
|
|
|
** second overrides the first, even though they were on different |
135
|
|
|
|
|
|
|
** file descriptors opened on different file names. |
136
|
|
|
|
|
|
|
** |
137
|
|
|
|
|
|
|
** Bummer. If you ask me, this is broken. Badly broken. It means |
138
|
|
|
|
|
|
|
** that we cannot use POSIX locks to synchronize file access among |
139
|
|
|
|
|
|
|
** competing threads of the same process. POSIX locks will work fine |
140
|
|
|
|
|
|
|
** to synchronize access for threads in separate processes, but not |
141
|
|
|
|
|
|
|
** threads within the same process. |
142
|
|
|
|
|
|
|
** |
143
|
|
|
|
|
|
|
** To work around the problem, SQLite has to manage file locks internally |
144
|
|
|
|
|
|
|
** on its own. Whenever a new database is opened, we have to find the |
145
|
|
|
|
|
|
|
** specific inode of the database file (the inode is determined by the |
146
|
|
|
|
|
|
|
** st_dev and st_ino fields of the stat structure that fstat() fills in) |
147
|
|
|
|
|
|
|
** and check for locks already existing on that inode. When locks are |
148
|
|
|
|
|
|
|
** created or removed, we have to look at our own internal record of the |
149
|
|
|
|
|
|
|
** locks to see if another thread has previously set a lock on that same |
150
|
|
|
|
|
|
|
** inode. |
151
|
|
|
|
|
|
|
** |
152
|
|
|
|
|
|
|
** The OsFile structure for POSIX is no longer just an integer file |
153
|
|
|
|
|
|
|
** descriptor. It is now a structure that holds the integer file |
154
|
|
|
|
|
|
|
** descriptor and a pointer to a structure that describes the internal |
155
|
|
|
|
|
|
|
** locks on the corresponding inode. There is one locking structure |
156
|
|
|
|
|
|
|
** per inode, so if the same inode is opened twice, both OsFile structures |
157
|
|
|
|
|
|
|
** point to the same locking structure. The locking structure keeps |
158
|
|
|
|
|
|
|
** a reference count (so we will know when to delete it) and a "cnt" |
159
|
|
|
|
|
|
|
** field that tells us its internal lock status. cnt==0 means the |
160
|
|
|
|
|
|
|
** file is unlocked. cnt==-1 means the file has an exclusive lock. |
161
|
|
|
|
|
|
|
** cnt>0 means there are cnt shared locks on the file. |
162
|
|
|
|
|
|
|
** |
163
|
|
|
|
|
|
|
** Any attempt to lock or unlock a file first checks the locking |
164
|
|
|
|
|
|
|
** structure. The fcntl() system call is only invoked to set a |
165
|
|
|
|
|
|
|
** POSIX lock if the internal lock structure transitions between |
166
|
|
|
|
|
|
|
** a locked and an unlocked state. |
167
|
|
|
|
|
|
|
** |
168
|
|
|
|
|
|
|
** 2004-Jan-11: |
169
|
|
|
|
|
|
|
** More recent discoveries about POSIX advisory locks. (The more |
170
|
|
|
|
|
|
|
** I discover, the more I realize the a POSIX advisory locks are |
171
|
|
|
|
|
|
|
** an abomination.) |
172
|
|
|
|
|
|
|
** |
173
|
|
|
|
|
|
|
** If you close a file descriptor that points to a file that has locks, |
174
|
|
|
|
|
|
|
** all locks on that file that are owned by the current process are |
175
|
|
|
|
|
|
|
** released. To work around this problem, each OsFile structure contains |
176
|
|
|
|
|
|
|
** a pointer to an openCnt structure. There is one openCnt structure |
177
|
|
|
|
|
|
|
** per open inode, which means that multiple OsFiles can point to a single |
178
|
|
|
|
|
|
|
** openCnt. When an attempt is made to close an OsFile, if there are |
179
|
|
|
|
|
|
|
** other OsFiles open on the same inode that are holding locks, the call |
180
|
|
|
|
|
|
|
** to close() the file descriptor is deferred until all of the locks clear. |
181
|
|
|
|
|
|
|
** The openCnt structure keeps a list of file descriptors that need to |
182
|
|
|
|
|
|
|
** be closed and that list is walked (and cleared) when the last lock |
183
|
|
|
|
|
|
|
** clears. |
184
|
|
|
|
|
|
|
** |
185
|
|
|
|
|
|
|
** First, under Linux threads, because each thread has a separate |
186
|
|
|
|
|
|
|
** process ID, lock operations in one thread do not override locks |
187
|
|
|
|
|
|
|
** to the same file in other threads. Linux threads behave like |
188
|
|
|
|
|
|
|
** separate processes in this respect. But, if you close a file |
189
|
|
|
|
|
|
|
** descriptor in linux threads, all locks are cleared, even locks |
190
|
|
|
|
|
|
|
** on other threads and even though the other threads have different |
191
|
|
|
|
|
|
|
** process IDs. Linux threads is inconsistent in this respect. |
192
|
|
|
|
|
|
|
** (I'm beginning to think that linux threads is an abomination too.) |
193
|
|
|
|
|
|
|
** The consequence of this all is that the hash table for the lockInfo |
194
|
|
|
|
|
|
|
** structure has to include the process id as part of its key because |
195
|
|
|
|
|
|
|
** locks in different threads are treated as distinct. But the |
196
|
|
|
|
|
|
|
** openCnt structure should not include the process id in its |
197
|
|
|
|
|
|
|
** key because close() clears lock on all threads, not just the current |
198
|
|
|
|
|
|
|
** thread. Were it not for this goofiness in linux threads, we could |
199
|
|
|
|
|
|
|
** combine the lockInfo and openCnt structures into a single structure. |
200
|
|
|
|
|
|
|
*/ |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
/* |
203
|
|
|
|
|
|
|
** An instance of the following structure serves as the key used |
204
|
|
|
|
|
|
|
** to locate a particular lockInfo structure given its inode. Note |
205
|
|
|
|
|
|
|
** that we have to include the process ID as part of the key. On some |
206
|
|
|
|
|
|
|
** threading implementations (ex: linux), each thread has a separate |
207
|
|
|
|
|
|
|
** process ID. |
208
|
|
|
|
|
|
|
*/ |
209
|
|
|
|
|
|
|
struct lockKey { |
210
|
|
|
|
|
|
|
dev_t dev; /* Device number */ |
211
|
|
|
|
|
|
|
ino_t ino; /* Inode number */ |
212
|
|
|
|
|
|
|
pid_t pid; /* Process ID */ |
213
|
|
|
|
|
|
|
}; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
/* |
216
|
|
|
|
|
|
|
** An instance of the following structure is allocated for each open |
217
|
|
|
|
|
|
|
** inode on each thread with a different process ID. (Threads have |
218
|
|
|
|
|
|
|
** different process IDs on linux, but not on most other unixes.) |
219
|
|
|
|
|
|
|
** |
220
|
|
|
|
|
|
|
** A single inode can have multiple file descriptors, so each OsFile |
221
|
|
|
|
|
|
|
** structure contains a pointer to an instance of this object and this |
222
|
|
|
|
|
|
|
** object keeps a count of the number of OsFiles pointing to it. |
223
|
|
|
|
|
|
|
*/ |
224
|
|
|
|
|
|
|
struct lockInfo { |
225
|
|
|
|
|
|
|
struct lockKey key; /* The lookup key */ |
226
|
|
|
|
|
|
|
int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */ |
227
|
|
|
|
|
|
|
int nRef; /* Number of pointers to this structure */ |
228
|
|
|
|
|
|
|
}; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
/* |
231
|
|
|
|
|
|
|
** An instance of the following structure serves as the key used |
232
|
|
|
|
|
|
|
** to locate a particular openCnt structure given its inode. This |
233
|
|
|
|
|
|
|
** is the same as the lockKey except that the process ID is omitted. |
234
|
|
|
|
|
|
|
*/ |
235
|
|
|
|
|
|
|
struct openKey { |
236
|
|
|
|
|
|
|
dev_t dev; /* Device number */ |
237
|
|
|
|
|
|
|
ino_t ino; /* Inode number */ |
238
|
|
|
|
|
|
|
}; |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
/* |
241
|
|
|
|
|
|
|
** An instance of the following structure is allocated for each open |
242
|
|
|
|
|
|
|
** inode. This structure keeps track of the number of locks on that |
243
|
|
|
|
|
|
|
** inode. If a close is attempted against an inode that is holding |
244
|
|
|
|
|
|
|
** locks, the close is deferred until all locks clear by adding the |
245
|
|
|
|
|
|
|
** file descriptor to be closed to the pending list. |
246
|
|
|
|
|
|
|
*/ |
247
|
|
|
|
|
|
|
struct openCnt { |
248
|
|
|
|
|
|
|
struct openKey key; /* The lookup key */ |
249
|
|
|
|
|
|
|
int nRef; /* Number of pointers to this structure */ |
250
|
|
|
|
|
|
|
int nLock; /* Number of outstanding locks */ |
251
|
|
|
|
|
|
|
int nPending; /* Number of pending close() operations */ |
252
|
|
|
|
|
|
|
int *aPending; /* Malloced space holding fd's awaiting a close() */ |
253
|
|
|
|
|
|
|
}; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
/* |
256
|
|
|
|
|
|
|
** These hash table maps inodes and process IDs into lockInfo and openCnt |
257
|
|
|
|
|
|
|
** structures. Access to these hash tables must be protected by a mutex. |
258
|
|
|
|
|
|
|
*/ |
259
|
|
|
|
|
|
|
static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; |
260
|
|
|
|
|
|
|
static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
/* |
263
|
|
|
|
|
|
|
** Release a lockInfo structure previously allocated by findLockInfo(). |
264
|
|
|
|
|
|
|
*/ |
265
|
151
|
|
|
|
|
|
static void releaseLockInfo(struct lockInfo *pLock){ |
266
|
151
|
|
|
|
|
|
pLock->nRef--; |
267
|
151
|
50
|
|
|
|
|
if( pLock->nRef==0 ){ |
268
|
151
|
|
|
|
|
|
sqliteHashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); |
269
|
151
|
|
|
|
|
|
sqliteFree(pLock); |
270
|
|
|
|
|
|
|
} |
271
|
151
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
/* |
274
|
|
|
|
|
|
|
** Release a openCnt structure previously allocated by findLockInfo(). |
275
|
|
|
|
|
|
|
*/ |
276
|
151
|
|
|
|
|
|
static void releaseOpenCnt(struct openCnt *pOpen){ |
277
|
151
|
|
|
|
|
|
pOpen->nRef--; |
278
|
151
|
50
|
|
|
|
|
if( pOpen->nRef==0 ){ |
279
|
151
|
|
|
|
|
|
sqliteHashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); |
280
|
151
|
|
|
|
|
|
sqliteFree(pOpen->aPending); |
281
|
151
|
|
|
|
|
|
sqliteFree(pOpen); |
282
|
|
|
|
|
|
|
} |
283
|
151
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
/* |
286
|
|
|
|
|
|
|
** Given a file descriptor, locate lockInfo and openCnt structures that |
287
|
|
|
|
|
|
|
** describes that file descriptor. Create a new ones if necessary. The |
288
|
|
|
|
|
|
|
** return values might be unset if an error occurs. |
289
|
|
|
|
|
|
|
** |
290
|
|
|
|
|
|
|
** Return the number of errors. |
291
|
|
|
|
|
|
|
*/ |
292
|
151
|
|
|
|
|
|
int findLockInfo( |
293
|
|
|
|
|
|
|
int fd, /* The file descriptor used in the key */ |
294
|
|
|
|
|
|
|
struct lockInfo **ppLock, /* Return the lockInfo structure here */ |
295
|
|
|
|
|
|
|
struct openCnt **ppOpen /* Return the openCnt structure here */ |
296
|
|
|
|
|
|
|
){ |
297
|
|
|
|
|
|
|
int rc; |
298
|
|
|
|
|
|
|
struct lockKey key1; |
299
|
|
|
|
|
|
|
struct openKey key2; |
300
|
|
|
|
|
|
|
struct stat statbuf; |
301
|
|
|
|
|
|
|
struct lockInfo *pLock; |
302
|
|
|
|
|
|
|
struct openCnt *pOpen; |
303
|
151
|
|
|
|
|
|
rc = fstat(fd, &statbuf); |
304
|
151
|
50
|
|
|
|
|
if( rc!=0 ) return 1; |
305
|
151
|
|
|
|
|
|
memset(&key1, 0, sizeof(key1)); |
306
|
151
|
|
|
|
|
|
key1.dev = statbuf.st_dev; |
307
|
151
|
|
|
|
|
|
key1.ino = statbuf.st_ino; |
308
|
151
|
|
|
|
|
|
key1.pid = getpid(); |
309
|
151
|
|
|
|
|
|
memset(&key2, 0, sizeof(key2)); |
310
|
151
|
|
|
|
|
|
key2.dev = statbuf.st_dev; |
311
|
151
|
|
|
|
|
|
key2.ino = statbuf.st_ino; |
312
|
151
|
|
|
|
|
|
pLock = (struct lockInfo*)sqliteHashFind(&lockHash, &key1, sizeof(key1)); |
313
|
151
|
50
|
|
|
|
|
if( pLock==0 ){ |
314
|
|
|
|
|
|
|
struct lockInfo *pOld; |
315
|
151
|
|
|
|
|
|
pLock = sqliteMallocRaw( sizeof(*pLock) ); |
316
|
151
|
50
|
|
|
|
|
if( pLock==0 ) return 1; |
317
|
151
|
|
|
|
|
|
pLock->key = key1; |
318
|
151
|
|
|
|
|
|
pLock->nRef = 1; |
319
|
151
|
|
|
|
|
|
pLock->cnt = 0; |
320
|
151
|
|
|
|
|
|
pOld = sqliteHashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); |
321
|
151
|
50
|
|
|
|
|
if( pOld!=0 ){ |
322
|
|
|
|
|
|
|
assert( pOld==pLock ); |
323
|
0
|
|
|
|
|
|
sqliteFree(pLock); |
324
|
151
|
|
|
|
|
|
return 1; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
}else{ |
327
|
0
|
|
|
|
|
|
pLock->nRef++; |
328
|
|
|
|
|
|
|
} |
329
|
151
|
|
|
|
|
|
*ppLock = pLock; |
330
|
151
|
|
|
|
|
|
pOpen = (struct openCnt*)sqliteHashFind(&openHash, &key2, sizeof(key2)); |
331
|
151
|
50
|
|
|
|
|
if( pOpen==0 ){ |
332
|
|
|
|
|
|
|
struct openCnt *pOld; |
333
|
151
|
|
|
|
|
|
pOpen = sqliteMallocRaw( sizeof(*pOpen) ); |
334
|
151
|
50
|
|
|
|
|
if( pOpen==0 ){ |
335
|
0
|
|
|
|
|
|
releaseLockInfo(pLock); |
336
|
0
|
|
|
|
|
|
return 1; |
337
|
|
|
|
|
|
|
} |
338
|
151
|
|
|
|
|
|
pOpen->key = key2; |
339
|
151
|
|
|
|
|
|
pOpen->nRef = 1; |
340
|
151
|
|
|
|
|
|
pOpen->nLock = 0; |
341
|
151
|
|
|
|
|
|
pOpen->nPending = 0; |
342
|
151
|
|
|
|
|
|
pOpen->aPending = 0; |
343
|
151
|
|
|
|
|
|
pOld = sqliteHashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); |
344
|
151
|
50
|
|
|
|
|
if( pOld!=0 ){ |
345
|
|
|
|
|
|
|
assert( pOld==pOpen ); |
346
|
0
|
|
|
|
|
|
sqliteFree(pOpen); |
347
|
0
|
|
|
|
|
|
releaseLockInfo(pLock); |
348
|
151
|
|
|
|
|
|
return 1; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
}else{ |
351
|
0
|
|
|
|
|
|
pOpen->nRef++; |
352
|
|
|
|
|
|
|
} |
353
|
151
|
|
|
|
|
|
*ppOpen = pOpen; |
354
|
151
|
|
|
|
|
|
return 0; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
#endif /** POSIX advisory lock work-around **/ |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
/* |
360
|
|
|
|
|
|
|
** If we compile with the SQLITE_TEST macro set, then the following block |
361
|
|
|
|
|
|
|
** of code will give us the ability to simulate a disk I/O error. This |
362
|
|
|
|
|
|
|
** is used for testing the I/O recovery logic. |
363
|
|
|
|
|
|
|
*/ |
364
|
|
|
|
|
|
|
#ifdef SQLITE_TEST |
365
|
|
|
|
|
|
|
int sqlite_io_error_pending = 0; |
366
|
|
|
|
|
|
|
#define SimulateIOError(A) \ |
367
|
|
|
|
|
|
|
if( sqlite_io_error_pending ) \ |
368
|
|
|
|
|
|
|
if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; } |
369
|
|
|
|
|
|
|
static void local_ioerr(){ |
370
|
|
|
|
|
|
|
sqlite_io_error_pending = 0; /* Really just a place to set a breakpoint */ |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
#else |
373
|
|
|
|
|
|
|
#define SimulateIOError(A) |
374
|
|
|
|
|
|
|
#endif |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
/* |
377
|
|
|
|
|
|
|
** When testing, keep a count of the number of open files. |
378
|
|
|
|
|
|
|
*/ |
379
|
|
|
|
|
|
|
#ifdef SQLITE_TEST |
380
|
|
|
|
|
|
|
int sqlite_open_file_count = 0; |
381
|
|
|
|
|
|
|
#define OpenCounter(X) sqlite_open_file_count+=(X) |
382
|
|
|
|
|
|
|
#else |
383
|
|
|
|
|
|
|
#define OpenCounter(X) |
384
|
|
|
|
|
|
|
#endif |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
/* |
388
|
|
|
|
|
|
|
** Delete the named file |
389
|
|
|
|
|
|
|
*/ |
390
|
98
|
|
|
|
|
|
int sqliteOsDelete(const char *zFilename){ |
391
|
|
|
|
|
|
|
#if OS_UNIX |
392
|
98
|
|
|
|
|
|
unlink(zFilename); |
393
|
|
|
|
|
|
|
#endif |
394
|
|
|
|
|
|
|
#if OS_WIN |
395
|
|
|
|
|
|
|
DeleteFile(zFilename); |
396
|
|
|
|
|
|
|
#endif |
397
|
|
|
|
|
|
|
#if OS_MAC |
398
|
|
|
|
|
|
|
unlink(zFilename); |
399
|
|
|
|
|
|
|
#endif |
400
|
98
|
|
|
|
|
|
return SQLITE_OK; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
/* |
404
|
|
|
|
|
|
|
** Return TRUE if the named file exists. |
405
|
|
|
|
|
|
|
*/ |
406
|
256
|
|
|
|
|
|
int sqliteOsFileExists(const char *zFilename){ |
407
|
|
|
|
|
|
|
#if OS_UNIX |
408
|
256
|
|
|
|
|
|
return access(zFilename, 0)==0; |
409
|
|
|
|
|
|
|
#endif |
410
|
|
|
|
|
|
|
#if OS_WIN |
411
|
|
|
|
|
|
|
return GetFileAttributes(zFilename) != 0xffffffff; |
412
|
|
|
|
|
|
|
#endif |
413
|
|
|
|
|
|
|
#if OS_MAC |
414
|
|
|
|
|
|
|
return access(zFilename, 0)==0; |
415
|
|
|
|
|
|
|
#endif |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
#if 0 /* NOT USED */ |
420
|
|
|
|
|
|
|
/* |
421
|
|
|
|
|
|
|
** Change the name of an existing file. |
422
|
|
|
|
|
|
|
*/ |
423
|
|
|
|
|
|
|
int sqliteOsFileRename(const char *zOldName, const char *zNewName){ |
424
|
|
|
|
|
|
|
#if OS_UNIX |
425
|
|
|
|
|
|
|
if( link(zOldName, zNewName) ){ |
426
|
|
|
|
|
|
|
return SQLITE_ERROR; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
unlink(zOldName); |
429
|
|
|
|
|
|
|
return SQLITE_OK; |
430
|
|
|
|
|
|
|
#endif |
431
|
|
|
|
|
|
|
#if OS_WIN |
432
|
|
|
|
|
|
|
if( !MoveFile(zOldName, zNewName) ){ |
433
|
|
|
|
|
|
|
return SQLITE_ERROR; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
return SQLITE_OK; |
436
|
|
|
|
|
|
|
#endif |
437
|
|
|
|
|
|
|
#if OS_MAC |
438
|
|
|
|
|
|
|
/**** FIX ME ***/ |
439
|
|
|
|
|
|
|
return SQLITE_ERROR; |
440
|
|
|
|
|
|
|
#endif |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
#endif /* NOT USED */ |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
/* |
445
|
|
|
|
|
|
|
** Attempt to open a file for both reading and writing. If that |
446
|
|
|
|
|
|
|
** fails, try opening it read-only. If the file does not exist, |
447
|
|
|
|
|
|
|
** try to create it. |
448
|
|
|
|
|
|
|
** |
449
|
|
|
|
|
|
|
** On success, a handle for the open file is written to *id |
450
|
|
|
|
|
|
|
** and *pReadonly is set to 0 if the file was opened for reading and |
451
|
|
|
|
|
|
|
** writing or 1 if the file was opened read-only. The function returns |
452
|
|
|
|
|
|
|
** SQLITE_OK. |
453
|
|
|
|
|
|
|
** |
454
|
|
|
|
|
|
|
** On failure, the function returns SQLITE_CANTOPEN and leaves |
455
|
|
|
|
|
|
|
** *id and *pReadonly unchanged. |
456
|
|
|
|
|
|
|
*/ |
457
|
25
|
|
|
|
|
|
int sqliteOsOpenReadWrite( |
458
|
|
|
|
|
|
|
const char *zFilename, |
459
|
|
|
|
|
|
|
OsFile *id, |
460
|
|
|
|
|
|
|
int *pReadonly |
461
|
|
|
|
|
|
|
){ |
462
|
|
|
|
|
|
|
#if OS_UNIX |
463
|
|
|
|
|
|
|
int rc; |
464
|
25
|
|
|
|
|
|
id->dirfd = -1; |
465
|
25
|
|
|
|
|
|
id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644); |
466
|
25
|
50
|
|
|
|
|
if( id->fd<0 ){ |
467
|
|
|
|
|
|
|
#ifdef EISDIR |
468
|
0
|
0
|
|
|
|
|
if( errno==EISDIR ){ |
469
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
#endif |
472
|
0
|
|
|
|
|
|
id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); |
473
|
0
|
0
|
|
|
|
|
if( id->fd<0 ){ |
474
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
475
|
|
|
|
|
|
|
} |
476
|
0
|
|
|
|
|
|
*pReadonly = 1; |
477
|
|
|
|
|
|
|
}else{ |
478
|
25
|
|
|
|
|
|
*pReadonly = 0; |
479
|
|
|
|
|
|
|
} |
480
|
25
|
|
|
|
|
|
sqliteOsEnterMutex(); |
481
|
25
|
|
|
|
|
|
rc = findLockInfo(id->fd, &id->pLock, &id->pOpen); |
482
|
25
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
483
|
25
|
50
|
|
|
|
|
if( rc ){ |
484
|
0
|
|
|
|
|
|
close(id->fd); |
485
|
0
|
|
|
|
|
|
return SQLITE_NOMEM; |
486
|
|
|
|
|
|
|
} |
487
|
25
|
|
|
|
|
|
id->locked = 0; |
488
|
|
|
|
|
|
|
TRACE3("OPEN %-3d %s\n", id->fd, zFilename); |
489
|
|
|
|
|
|
|
OpenCounter(+1); |
490
|
25
|
|
|
|
|
|
return SQLITE_OK; |
491
|
|
|
|
|
|
|
#endif |
492
|
|
|
|
|
|
|
#if OS_WIN |
493
|
|
|
|
|
|
|
HANDLE h = CreateFile(zFilename, |
494
|
|
|
|
|
|
|
GENERIC_READ | GENERIC_WRITE, |
495
|
|
|
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, |
496
|
|
|
|
|
|
|
NULL, |
497
|
|
|
|
|
|
|
OPEN_ALWAYS, |
498
|
|
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, |
499
|
|
|
|
|
|
|
NULL |
500
|
|
|
|
|
|
|
); |
501
|
|
|
|
|
|
|
if( h==INVALID_HANDLE_VALUE ){ |
502
|
|
|
|
|
|
|
h = CreateFile(zFilename, |
503
|
|
|
|
|
|
|
GENERIC_READ, |
504
|
|
|
|
|
|
|
FILE_SHARE_READ, |
505
|
|
|
|
|
|
|
NULL, |
506
|
|
|
|
|
|
|
OPEN_ALWAYS, |
507
|
|
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, |
508
|
|
|
|
|
|
|
NULL |
509
|
|
|
|
|
|
|
); |
510
|
|
|
|
|
|
|
if( h==INVALID_HANDLE_VALUE ){ |
511
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
*pReadonly = 1; |
514
|
|
|
|
|
|
|
}else{ |
515
|
|
|
|
|
|
|
*pReadonly = 0; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
id->h = h; |
518
|
|
|
|
|
|
|
id->locked = 0; |
519
|
|
|
|
|
|
|
OpenCounter(+1); |
520
|
|
|
|
|
|
|
return SQLITE_OK; |
521
|
|
|
|
|
|
|
#endif |
522
|
|
|
|
|
|
|
#if OS_MAC |
523
|
|
|
|
|
|
|
FSSpec fsSpec; |
524
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
525
|
|
|
|
|
|
|
HFSUniStr255 dfName; |
526
|
|
|
|
|
|
|
FSRef fsRef; |
527
|
|
|
|
|
|
|
if( __path2fss(zFilename, &fsSpec) != noErr ){ |
528
|
|
|
|
|
|
|
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) |
529
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) |
532
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
533
|
|
|
|
|
|
|
FSGetDataForkName(&dfName); |
534
|
|
|
|
|
|
|
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, |
535
|
|
|
|
|
|
|
fsRdWrShPerm, &(id->refNum)) != noErr ){ |
536
|
|
|
|
|
|
|
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, |
537
|
|
|
|
|
|
|
fsRdWrPerm, &(id->refNum)) != noErr ){ |
538
|
|
|
|
|
|
|
if (FSOpenFork(&fsRef, dfName.length, dfName.unicode, |
539
|
|
|
|
|
|
|
fsRdPerm, &(id->refNum)) != noErr ) |
540
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
541
|
|
|
|
|
|
|
else |
542
|
|
|
|
|
|
|
*pReadonly = 1; |
543
|
|
|
|
|
|
|
} else |
544
|
|
|
|
|
|
|
*pReadonly = 0; |
545
|
|
|
|
|
|
|
} else |
546
|
|
|
|
|
|
|
*pReadonly = 0; |
547
|
|
|
|
|
|
|
# else |
548
|
|
|
|
|
|
|
__path2fss(zFilename, &fsSpec); |
549
|
|
|
|
|
|
|
if( !sqliteOsFileExists(zFilename) ){ |
550
|
|
|
|
|
|
|
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) |
551
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){ |
554
|
|
|
|
|
|
|
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){ |
555
|
|
|
|
|
|
|
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr ) |
556
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
557
|
|
|
|
|
|
|
else |
558
|
|
|
|
|
|
|
*pReadonly = 1; |
559
|
|
|
|
|
|
|
} else |
560
|
|
|
|
|
|
|
*pReadonly = 0; |
561
|
|
|
|
|
|
|
} else |
562
|
|
|
|
|
|
|
*pReadonly = 0; |
563
|
|
|
|
|
|
|
# endif |
564
|
|
|
|
|
|
|
if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){ |
565
|
|
|
|
|
|
|
id->refNumRF = -1; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
id->locked = 0; |
568
|
|
|
|
|
|
|
id->delOnClose = 0; |
569
|
|
|
|
|
|
|
OpenCounter(+1); |
570
|
|
|
|
|
|
|
return SQLITE_OK; |
571
|
|
|
|
|
|
|
#endif |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
/* |
576
|
|
|
|
|
|
|
** Attempt to open a new file for exclusive access by this process. |
577
|
|
|
|
|
|
|
** The file will be opened for both reading and writing. To avoid |
578
|
|
|
|
|
|
|
** a potential security problem, we do not allow the file to have |
579
|
|
|
|
|
|
|
** previously existed. Nor do we allow the file to be a symbolic |
580
|
|
|
|
|
|
|
** link. |
581
|
|
|
|
|
|
|
** |
582
|
|
|
|
|
|
|
** If delFlag is true, then make arrangements to automatically delete |
583
|
|
|
|
|
|
|
** the file when it is closed. |
584
|
|
|
|
|
|
|
** |
585
|
|
|
|
|
|
|
** On success, write the file handle into *id and return SQLITE_OK. |
586
|
|
|
|
|
|
|
** |
587
|
|
|
|
|
|
|
** On failure, return SQLITE_CANTOPEN. |
588
|
|
|
|
|
|
|
*/ |
589
|
126
|
|
|
|
|
|
int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ |
590
|
|
|
|
|
|
|
#if OS_UNIX |
591
|
|
|
|
|
|
|
int rc; |
592
|
126
|
50
|
|
|
|
|
if( access(zFilename, 0)==0 ){ |
593
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
594
|
|
|
|
|
|
|
} |
595
|
126
|
|
|
|
|
|
id->dirfd = -1; |
596
|
126
|
|
|
|
|
|
id->fd = open(zFilename, |
597
|
|
|
|
|
|
|
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600); |
598
|
126
|
50
|
|
|
|
|
if( id->fd<0 ){ |
599
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
600
|
|
|
|
|
|
|
} |
601
|
126
|
|
|
|
|
|
sqliteOsEnterMutex(); |
602
|
126
|
|
|
|
|
|
rc = findLockInfo(id->fd, &id->pLock, &id->pOpen); |
603
|
126
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
604
|
126
|
50
|
|
|
|
|
if( rc ){ |
605
|
0
|
|
|
|
|
|
close(id->fd); |
606
|
0
|
|
|
|
|
|
unlink(zFilename); |
607
|
0
|
|
|
|
|
|
return SQLITE_NOMEM; |
608
|
|
|
|
|
|
|
} |
609
|
126
|
|
|
|
|
|
id->locked = 0; |
610
|
126
|
100
|
|
|
|
|
if( delFlag ){ |
611
|
51
|
|
|
|
|
|
unlink(zFilename); |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename); |
614
|
|
|
|
|
|
|
OpenCounter(+1); |
615
|
126
|
|
|
|
|
|
return SQLITE_OK; |
616
|
|
|
|
|
|
|
#endif |
617
|
|
|
|
|
|
|
#if OS_WIN |
618
|
|
|
|
|
|
|
HANDLE h; |
619
|
|
|
|
|
|
|
int fileflags; |
620
|
|
|
|
|
|
|
if( delFlag ){ |
621
|
|
|
|
|
|
|
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS |
622
|
|
|
|
|
|
|
| FILE_FLAG_DELETE_ON_CLOSE; |
623
|
|
|
|
|
|
|
}else{ |
624
|
|
|
|
|
|
|
fileflags = FILE_FLAG_RANDOM_ACCESS; |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
h = CreateFile(zFilename, |
627
|
|
|
|
|
|
|
GENERIC_READ | GENERIC_WRITE, |
628
|
|
|
|
|
|
|
0, |
629
|
|
|
|
|
|
|
NULL, |
630
|
|
|
|
|
|
|
CREATE_ALWAYS, |
631
|
|
|
|
|
|
|
fileflags, |
632
|
|
|
|
|
|
|
NULL |
633
|
|
|
|
|
|
|
); |
634
|
|
|
|
|
|
|
if( h==INVALID_HANDLE_VALUE ){ |
635
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
id->h = h; |
638
|
|
|
|
|
|
|
id->locked = 0; |
639
|
|
|
|
|
|
|
OpenCounter(+1); |
640
|
|
|
|
|
|
|
return SQLITE_OK; |
641
|
|
|
|
|
|
|
#endif |
642
|
|
|
|
|
|
|
#if OS_MAC |
643
|
|
|
|
|
|
|
FSSpec fsSpec; |
644
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
645
|
|
|
|
|
|
|
HFSUniStr255 dfName; |
646
|
|
|
|
|
|
|
FSRef fsRef; |
647
|
|
|
|
|
|
|
__path2fss(zFilename, &fsSpec); |
648
|
|
|
|
|
|
|
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) |
649
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
650
|
|
|
|
|
|
|
if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) |
651
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
652
|
|
|
|
|
|
|
FSGetDataForkName(&dfName); |
653
|
|
|
|
|
|
|
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, |
654
|
|
|
|
|
|
|
fsRdWrPerm, &(id->refNum)) != noErr ) |
655
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
656
|
|
|
|
|
|
|
# else |
657
|
|
|
|
|
|
|
__path2fss(zFilename, &fsSpec); |
658
|
|
|
|
|
|
|
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) |
659
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
660
|
|
|
|
|
|
|
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ) |
661
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
662
|
|
|
|
|
|
|
# endif |
663
|
|
|
|
|
|
|
id->refNumRF = -1; |
664
|
|
|
|
|
|
|
id->locked = 0; |
665
|
|
|
|
|
|
|
id->delOnClose = delFlag; |
666
|
|
|
|
|
|
|
if (delFlag) |
667
|
|
|
|
|
|
|
id->pathToDel = sqliteOsFullPathname(zFilename); |
668
|
|
|
|
|
|
|
OpenCounter(+1); |
669
|
|
|
|
|
|
|
return SQLITE_OK; |
670
|
|
|
|
|
|
|
#endif |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
/* |
674
|
|
|
|
|
|
|
** Attempt to open a new file for read-only access. |
675
|
|
|
|
|
|
|
** |
676
|
|
|
|
|
|
|
** On success, write the file handle into *id and return SQLITE_OK. |
677
|
|
|
|
|
|
|
** |
678
|
|
|
|
|
|
|
** On failure, return SQLITE_CANTOPEN. |
679
|
|
|
|
|
|
|
*/ |
680
|
0
|
|
|
|
|
|
int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){ |
681
|
|
|
|
|
|
|
#if OS_UNIX |
682
|
|
|
|
|
|
|
int rc; |
683
|
0
|
|
|
|
|
|
id->dirfd = -1; |
684
|
0
|
|
|
|
|
|
id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); |
685
|
0
|
0
|
|
|
|
|
if( id->fd<0 ){ |
686
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
687
|
|
|
|
|
|
|
} |
688
|
0
|
|
|
|
|
|
sqliteOsEnterMutex(); |
689
|
0
|
|
|
|
|
|
rc = findLockInfo(id->fd, &id->pLock, &id->pOpen); |
690
|
0
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
691
|
0
|
0
|
|
|
|
|
if( rc ){ |
692
|
0
|
|
|
|
|
|
close(id->fd); |
693
|
0
|
|
|
|
|
|
return SQLITE_NOMEM; |
694
|
|
|
|
|
|
|
} |
695
|
0
|
|
|
|
|
|
id->locked = 0; |
696
|
|
|
|
|
|
|
TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename); |
697
|
|
|
|
|
|
|
OpenCounter(+1); |
698
|
0
|
|
|
|
|
|
return SQLITE_OK; |
699
|
|
|
|
|
|
|
#endif |
700
|
|
|
|
|
|
|
#if OS_WIN |
701
|
|
|
|
|
|
|
HANDLE h = CreateFile(zFilename, |
702
|
|
|
|
|
|
|
GENERIC_READ, |
703
|
|
|
|
|
|
|
0, |
704
|
|
|
|
|
|
|
NULL, |
705
|
|
|
|
|
|
|
OPEN_EXISTING, |
706
|
|
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, |
707
|
|
|
|
|
|
|
NULL |
708
|
|
|
|
|
|
|
); |
709
|
|
|
|
|
|
|
if( h==INVALID_HANDLE_VALUE ){ |
710
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
711
|
|
|
|
|
|
|
} |
712
|
|
|
|
|
|
|
id->h = h; |
713
|
|
|
|
|
|
|
id->locked = 0; |
714
|
|
|
|
|
|
|
OpenCounter(+1); |
715
|
|
|
|
|
|
|
return SQLITE_OK; |
716
|
|
|
|
|
|
|
#endif |
717
|
|
|
|
|
|
|
#if OS_MAC |
718
|
|
|
|
|
|
|
FSSpec fsSpec; |
719
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
720
|
|
|
|
|
|
|
HFSUniStr255 dfName; |
721
|
|
|
|
|
|
|
FSRef fsRef; |
722
|
|
|
|
|
|
|
if( __path2fss(zFilename, &fsSpec) != noErr ) |
723
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
724
|
|
|
|
|
|
|
if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) |
725
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
726
|
|
|
|
|
|
|
FSGetDataForkName(&dfName); |
727
|
|
|
|
|
|
|
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, |
728
|
|
|
|
|
|
|
fsRdPerm, &(id->refNum)) != noErr ) |
729
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
730
|
|
|
|
|
|
|
# else |
731
|
|
|
|
|
|
|
__path2fss(zFilename, &fsSpec); |
732
|
|
|
|
|
|
|
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr ) |
733
|
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
734
|
|
|
|
|
|
|
# endif |
735
|
|
|
|
|
|
|
if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){ |
736
|
|
|
|
|
|
|
id->refNumRF = -1; |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
id->locked = 0; |
739
|
|
|
|
|
|
|
id->delOnClose = 0; |
740
|
|
|
|
|
|
|
OpenCounter(+1); |
741
|
|
|
|
|
|
|
return SQLITE_OK; |
742
|
|
|
|
|
|
|
#endif |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
/* |
746
|
|
|
|
|
|
|
** Attempt to open a file descriptor for the directory that contains a |
747
|
|
|
|
|
|
|
** file. This file descriptor can be used to fsync() the directory |
748
|
|
|
|
|
|
|
** in order to make sure the creation of a new file is actually written |
749
|
|
|
|
|
|
|
** to disk. |
750
|
|
|
|
|
|
|
** |
751
|
|
|
|
|
|
|
** This routine is only meaningful for Unix. It is a no-op under |
752
|
|
|
|
|
|
|
** windows since windows does not support hard links. |
753
|
|
|
|
|
|
|
** |
754
|
|
|
|
|
|
|
** On success, a handle for a previously open file is at *id is |
755
|
|
|
|
|
|
|
** updated with the new directory file descriptor and SQLITE_OK is |
756
|
|
|
|
|
|
|
** returned. |
757
|
|
|
|
|
|
|
** |
758
|
|
|
|
|
|
|
** On failure, the function returns SQLITE_CANTOPEN and leaves |
759
|
|
|
|
|
|
|
** *id unchanged. |
760
|
|
|
|
|
|
|
*/ |
761
|
98
|
|
|
|
|
|
int sqliteOsOpenDirectory( |
762
|
|
|
|
|
|
|
const char *zDirname, |
763
|
|
|
|
|
|
|
OsFile *id |
764
|
|
|
|
|
|
|
){ |
765
|
|
|
|
|
|
|
#if OS_UNIX |
766
|
98
|
50
|
|
|
|
|
if( id->fd<0 ){ |
767
|
|
|
|
|
|
|
/* Do not open the directory if the corresponding file is not already |
768
|
|
|
|
|
|
|
** open. */ |
769
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
assert( id->dirfd<0 ); |
772
|
98
|
|
|
|
|
|
id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644); |
773
|
98
|
50
|
|
|
|
|
if( id->dirfd<0 ){ |
774
|
0
|
|
|
|
|
|
return SQLITE_CANTOPEN; |
775
|
|
|
|
|
|
|
} |
776
|
|
|
|
|
|
|
TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname); |
777
|
|
|
|
|
|
|
#endif |
778
|
98
|
|
|
|
|
|
return SQLITE_OK; |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
/* |
782
|
|
|
|
|
|
|
** If the following global variable points to a string which is the |
783
|
|
|
|
|
|
|
** name of a directory, then that directory will be used to store |
784
|
|
|
|
|
|
|
** temporary files. |
785
|
|
|
|
|
|
|
*/ |
786
|
|
|
|
|
|
|
const char *sqlite_temp_directory = 0; |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
/* |
789
|
|
|
|
|
|
|
** Create a temporary file name in zBuf. zBuf must be big enough to |
790
|
|
|
|
|
|
|
** hold at least SQLITE_TEMPNAME_SIZE characters. |
791
|
|
|
|
|
|
|
*/ |
792
|
28
|
|
|
|
|
|
int sqliteOsTempFileName(char *zBuf){ |
793
|
|
|
|
|
|
|
#if OS_UNIX |
794
|
|
|
|
|
|
|
static const char *azDirs[] = { |
795
|
|
|
|
|
|
|
0, |
796
|
|
|
|
|
|
|
"/var/tmp", |
797
|
|
|
|
|
|
|
"/usr/tmp", |
798
|
|
|
|
|
|
|
"/tmp", |
799
|
|
|
|
|
|
|
".", |
800
|
|
|
|
|
|
|
}; |
801
|
|
|
|
|
|
|
static unsigned char zChars[] = |
802
|
|
|
|
|
|
|
"abcdefghijklmnopqrstuvwxyz" |
803
|
|
|
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
804
|
|
|
|
|
|
|
"0123456789"; |
805
|
|
|
|
|
|
|
int i, j; |
806
|
|
|
|
|
|
|
struct stat buf; |
807
|
28
|
|
|
|
|
|
const char *zDir = "."; |
808
|
28
|
|
|
|
|
|
azDirs[0] = sqlite_temp_directory; |
809
|
56
|
50
|
|
|
|
|
for(i=0; i
|
810
|
56
|
100
|
|
|
|
|
if( azDirs[i]==0 ) continue; |
811
|
28
|
50
|
|
|
|
|
if( stat(azDirs[i], &buf) ) continue; |
812
|
28
|
50
|
|
|
|
|
if( !S_ISDIR(buf.st_mode) ) continue; |
813
|
28
|
50
|
|
|
|
|
if( access(azDirs[i], 07) ) continue; |
814
|
28
|
|
|
|
|
|
zDir = azDirs[i]; |
815
|
28
|
|
|
|
|
|
break; |
816
|
|
|
|
|
|
|
} |
817
|
|
|
|
|
|
|
do{ |
818
|
28
|
|
|
|
|
|
sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir); |
819
|
28
|
|
|
|
|
|
j = strlen(zBuf); |
820
|
28
|
|
|
|
|
|
sqliteRandomness(15, &zBuf[j]); |
821
|
448
|
100
|
|
|
|
|
for(i=0; i<15; i++, j++){ |
822
|
420
|
|
|
|
|
|
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
823
|
|
|
|
|
|
|
} |
824
|
28
|
|
|
|
|
|
zBuf[j] = 0; |
825
|
28
|
50
|
|
|
|
|
}while( access(zBuf,0)==0 ); |
826
|
|
|
|
|
|
|
#endif |
827
|
|
|
|
|
|
|
#if OS_WIN |
828
|
|
|
|
|
|
|
static char zChars[] = |
829
|
|
|
|
|
|
|
"abcdefghijklmnopqrstuvwxyz" |
830
|
|
|
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
831
|
|
|
|
|
|
|
"0123456789"; |
832
|
|
|
|
|
|
|
int i, j; |
833
|
|
|
|
|
|
|
const char *zDir; |
834
|
|
|
|
|
|
|
char zTempPath[SQLITE_TEMPNAME_SIZE]; |
835
|
|
|
|
|
|
|
if( sqlite_temp_directory==0 ){ |
836
|
|
|
|
|
|
|
GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath); |
837
|
|
|
|
|
|
|
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} |
838
|
|
|
|
|
|
|
zTempPath[i] = 0; |
839
|
|
|
|
|
|
|
zDir = zTempPath; |
840
|
|
|
|
|
|
|
}else{ |
841
|
|
|
|
|
|
|
zDir = sqlite_temp_directory; |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
for(;;){ |
844
|
|
|
|
|
|
|
sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zDir); |
845
|
|
|
|
|
|
|
j = strlen(zBuf); |
846
|
|
|
|
|
|
|
sqliteRandomness(15, &zBuf[j]); |
847
|
|
|
|
|
|
|
for(i=0; i<15; i++, j++){ |
848
|
|
|
|
|
|
|
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
zBuf[j] = 0; |
851
|
|
|
|
|
|
|
if( !sqliteOsFileExists(zBuf) ) break; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
#endif |
854
|
|
|
|
|
|
|
#if OS_MAC |
855
|
|
|
|
|
|
|
static char zChars[] = |
856
|
|
|
|
|
|
|
"abcdefghijklmnopqrstuvwxyz" |
857
|
|
|
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
858
|
|
|
|
|
|
|
"0123456789"; |
859
|
|
|
|
|
|
|
int i, j; |
860
|
|
|
|
|
|
|
char *zDir; |
861
|
|
|
|
|
|
|
char zTempPath[SQLITE_TEMPNAME_SIZE]; |
862
|
|
|
|
|
|
|
char zdirName[32]; |
863
|
|
|
|
|
|
|
CInfoPBRec infoRec; |
864
|
|
|
|
|
|
|
Str31 dirName; |
865
|
|
|
|
|
|
|
memset(&infoRec, 0, sizeof(infoRec)); |
866
|
|
|
|
|
|
|
memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE); |
867
|
|
|
|
|
|
|
if( sqlite_temp_directory!=0 ){ |
868
|
|
|
|
|
|
|
zDir = sqlite_temp_directory; |
869
|
|
|
|
|
|
|
}else if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, |
870
|
|
|
|
|
|
|
&(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){ |
871
|
|
|
|
|
|
|
infoRec.dirInfo.ioNamePtr = dirName; |
872
|
|
|
|
|
|
|
do{ |
873
|
|
|
|
|
|
|
infoRec.dirInfo.ioFDirIndex = -1; |
874
|
|
|
|
|
|
|
infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID; |
875
|
|
|
|
|
|
|
if( PBGetCatInfoSync(&infoRec) == noErr ){ |
876
|
|
|
|
|
|
|
CopyPascalStringToC(dirName, zdirName); |
877
|
|
|
|
|
|
|
i = strlen(zdirName); |
878
|
|
|
|
|
|
|
memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath)); |
879
|
|
|
|
|
|
|
strcpy(zTempPath, zdirName); |
880
|
|
|
|
|
|
|
zTempPath[i] = ':'; |
881
|
|
|
|
|
|
|
}else{ |
882
|
|
|
|
|
|
|
*zTempPath = 0; |
883
|
|
|
|
|
|
|
break; |
884
|
|
|
|
|
|
|
} |
885
|
|
|
|
|
|
|
} while( infoRec.dirInfo.ioDrDirID != fsRtDirID ); |
886
|
|
|
|
|
|
|
zDir = zTempPath; |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
if( zDir[0]==0 ){ |
889
|
|
|
|
|
|
|
getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24); |
890
|
|
|
|
|
|
|
zDir = zTempPath; |
891
|
|
|
|
|
|
|
} |
892
|
|
|
|
|
|
|
for(;;){ |
893
|
|
|
|
|
|
|
sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zDir); |
894
|
|
|
|
|
|
|
j = strlen(zBuf); |
895
|
|
|
|
|
|
|
sqliteRandomness(15, &zBuf[j]); |
896
|
|
|
|
|
|
|
for(i=0; i<15; i++, j++){ |
897
|
|
|
|
|
|
|
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
898
|
|
|
|
|
|
|
} |
899
|
|
|
|
|
|
|
zBuf[j] = 0; |
900
|
|
|
|
|
|
|
if( !sqliteOsFileExists(zBuf) ) break; |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
#endif |
903
|
28
|
|
|
|
|
|
return SQLITE_OK; |
904
|
|
|
|
|
|
|
} |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
/* |
907
|
|
|
|
|
|
|
** Close a file. |
908
|
|
|
|
|
|
|
*/ |
909
|
151
|
|
|
|
|
|
int sqliteOsClose(OsFile *id){ |
910
|
|
|
|
|
|
|
#if OS_UNIX |
911
|
151
|
|
|
|
|
|
sqliteOsUnlock(id); |
912
|
151
|
100
|
|
|
|
|
if( id->dirfd>=0 ) close(id->dirfd); |
913
|
151
|
|
|
|
|
|
id->dirfd = -1; |
914
|
151
|
|
|
|
|
|
sqliteOsEnterMutex(); |
915
|
151
|
50
|
|
|
|
|
if( id->pOpen->nLock ){ |
916
|
|
|
|
|
|
|
/* If there are outstanding locks, do not actually close the file just |
917
|
|
|
|
|
|
|
** yet because that would clear those locks. Instead, add the file |
918
|
|
|
|
|
|
|
** descriptor to pOpen->aPending. It will be automatically closed when |
919
|
|
|
|
|
|
|
** the last lock is cleared. |
920
|
|
|
|
|
|
|
*/ |
921
|
|
|
|
|
|
|
int *aNew; |
922
|
0
|
|
|
|
|
|
struct openCnt *pOpen = id->pOpen; |
923
|
0
|
|
|
|
|
|
pOpen->nPending++; |
924
|
0
|
|
|
|
|
|
aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) ); |
925
|
0
|
0
|
|
|
|
|
if( aNew==0 ){ |
926
|
|
|
|
|
|
|
/* If a malloc fails, just leak the file descriptor */ |
927
|
|
|
|
|
|
|
}else{ |
928
|
0
|
|
|
|
|
|
pOpen->aPending = aNew; |
929
|
0
|
|
|
|
|
|
pOpen->aPending[pOpen->nPending-1] = id->fd; |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
}else{ |
932
|
|
|
|
|
|
|
/* There are no outstanding locks so we can close the file immediately */ |
933
|
151
|
|
|
|
|
|
close(id->fd); |
934
|
|
|
|
|
|
|
} |
935
|
151
|
|
|
|
|
|
releaseLockInfo(id->pLock); |
936
|
151
|
|
|
|
|
|
releaseOpenCnt(id->pOpen); |
937
|
151
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
938
|
|
|
|
|
|
|
TRACE2("CLOSE %-3d\n", id->fd); |
939
|
|
|
|
|
|
|
OpenCounter(-1); |
940
|
151
|
|
|
|
|
|
return SQLITE_OK; |
941
|
|
|
|
|
|
|
#endif |
942
|
|
|
|
|
|
|
#if OS_WIN |
943
|
|
|
|
|
|
|
CloseHandle(id->h); |
944
|
|
|
|
|
|
|
OpenCounter(-1); |
945
|
|
|
|
|
|
|
return SQLITE_OK; |
946
|
|
|
|
|
|
|
#endif |
947
|
|
|
|
|
|
|
#if OS_MAC |
948
|
|
|
|
|
|
|
if( id->refNumRF!=-1 ) |
949
|
|
|
|
|
|
|
FSClose(id->refNumRF); |
950
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
951
|
|
|
|
|
|
|
FSCloseFork(id->refNum); |
952
|
|
|
|
|
|
|
# else |
953
|
|
|
|
|
|
|
FSClose(id->refNum); |
954
|
|
|
|
|
|
|
# endif |
955
|
|
|
|
|
|
|
if( id->delOnClose ){ |
956
|
|
|
|
|
|
|
unlink(id->pathToDel); |
957
|
|
|
|
|
|
|
sqliteFree(id->pathToDel); |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
OpenCounter(-1); |
960
|
|
|
|
|
|
|
return SQLITE_OK; |
961
|
|
|
|
|
|
|
#endif |
962
|
|
|
|
|
|
|
} |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
/* |
965
|
|
|
|
|
|
|
** Read data from a file into a buffer. Return SQLITE_OK if all |
966
|
|
|
|
|
|
|
** bytes were read successfully and SQLITE_IOERR if anything goes |
967
|
|
|
|
|
|
|
** wrong. |
968
|
|
|
|
|
|
|
*/ |
969
|
492
|
|
|
|
|
|
int sqliteOsRead(OsFile *id, void *pBuf, int amt){ |
970
|
|
|
|
|
|
|
#if OS_UNIX |
971
|
|
|
|
|
|
|
int got; |
972
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
973
|
|
|
|
|
|
|
TIMER_START; |
974
|
492
|
|
|
|
|
|
got = read(id->fd, pBuf, amt); |
975
|
|
|
|
|
|
|
TIMER_END; |
976
|
|
|
|
|
|
|
TRACE4("READ %-3d %7d %d\n", id->fd, last_page, elapse); |
977
|
|
|
|
|
|
|
SEEK(0); |
978
|
|
|
|
|
|
|
/* if( got<0 ) got = 0; */ |
979
|
492
|
50
|
|
|
|
|
if( got==amt ){ |
980
|
492
|
|
|
|
|
|
return SQLITE_OK; |
981
|
|
|
|
|
|
|
}else{ |
982
|
0
|
|
|
|
|
|
return SQLITE_IOERR; |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
#endif |
985
|
|
|
|
|
|
|
#if OS_WIN |
986
|
|
|
|
|
|
|
DWORD got; |
987
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
988
|
|
|
|
|
|
|
TRACE2("READ %d\n", last_page); |
989
|
|
|
|
|
|
|
if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ |
990
|
|
|
|
|
|
|
got = 0; |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
if( got==(DWORD)amt ){ |
993
|
|
|
|
|
|
|
return SQLITE_OK; |
994
|
|
|
|
|
|
|
}else{ |
995
|
|
|
|
|
|
|
return SQLITE_IOERR; |
996
|
|
|
|
|
|
|
} |
997
|
|
|
|
|
|
|
#endif |
998
|
|
|
|
|
|
|
#if OS_MAC |
999
|
|
|
|
|
|
|
int got; |
1000
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1001
|
|
|
|
|
|
|
TRACE2("READ %d\n", last_page); |
1002
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
1003
|
|
|
|
|
|
|
FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got); |
1004
|
|
|
|
|
|
|
# else |
1005
|
|
|
|
|
|
|
got = amt; |
1006
|
|
|
|
|
|
|
FSRead(id->refNum, &got, pBuf); |
1007
|
|
|
|
|
|
|
# endif |
1008
|
|
|
|
|
|
|
if( got==amt ){ |
1009
|
|
|
|
|
|
|
return SQLITE_OK; |
1010
|
|
|
|
|
|
|
}else{ |
1011
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
#endif |
1014
|
|
|
|
|
|
|
} |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
/* |
1017
|
|
|
|
|
|
|
** Write data from a buffer into a file. Return SQLITE_OK on success |
1018
|
|
|
|
|
|
|
** or some other error code on failure. |
1019
|
|
|
|
|
|
|
*/ |
1020
|
819
|
|
|
|
|
|
int sqliteOsWrite(OsFile *id, const void *pBuf, int amt){ |
1021
|
|
|
|
|
|
|
#if OS_UNIX |
1022
|
819
|
|
|
|
|
|
int wrote = 0; |
1023
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1024
|
|
|
|
|
|
|
TIMER_START; |
1025
|
1638
|
100
|
|
|
|
|
while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){ |
|
|
50
|
|
|
|
|
|
1026
|
819
|
|
|
|
|
|
amt -= wrote; |
1027
|
819
|
|
|
|
|
|
pBuf = &((char*)pBuf)[wrote]; |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
TIMER_END; |
1030
|
|
|
|
|
|
|
TRACE4("WRITE %-3d %7d %d\n", id->fd, last_page, elapse); |
1031
|
|
|
|
|
|
|
SEEK(0); |
1032
|
819
|
50
|
|
|
|
|
if( amt>0 ){ |
1033
|
0
|
|
|
|
|
|
return SQLITE_FULL; |
1034
|
|
|
|
|
|
|
} |
1035
|
819
|
|
|
|
|
|
return SQLITE_OK; |
1036
|
|
|
|
|
|
|
#endif |
1037
|
|
|
|
|
|
|
#if OS_WIN |
1038
|
|
|
|
|
|
|
int rc; |
1039
|
|
|
|
|
|
|
DWORD wrote; |
1040
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1041
|
|
|
|
|
|
|
TRACE2("WRITE %d\n", last_page); |
1042
|
|
|
|
|
|
|
while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){ |
1043
|
|
|
|
|
|
|
amt -= wrote; |
1044
|
|
|
|
|
|
|
pBuf = &((char*)pBuf)[wrote]; |
1045
|
|
|
|
|
|
|
} |
1046
|
|
|
|
|
|
|
if( !rc || amt>(int)wrote ){ |
1047
|
|
|
|
|
|
|
return SQLITE_FULL; |
1048
|
|
|
|
|
|
|
} |
1049
|
|
|
|
|
|
|
return SQLITE_OK; |
1050
|
|
|
|
|
|
|
#endif |
1051
|
|
|
|
|
|
|
#if OS_MAC |
1052
|
|
|
|
|
|
|
OSErr oserr; |
1053
|
|
|
|
|
|
|
int wrote = 0; |
1054
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1055
|
|
|
|
|
|
|
TRACE2("WRITE %d\n", last_page); |
1056
|
|
|
|
|
|
|
while( amt>0 ){ |
1057
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
1058
|
|
|
|
|
|
|
oserr = FSWriteFork(id->refNum, fsAtMark, 0, |
1059
|
|
|
|
|
|
|
(ByteCount)amt, pBuf, (ByteCount*)&wrote); |
1060
|
|
|
|
|
|
|
# else |
1061
|
|
|
|
|
|
|
wrote = amt; |
1062
|
|
|
|
|
|
|
oserr = FSWrite(id->refNum, &wrote, pBuf); |
1063
|
|
|
|
|
|
|
# endif |
1064
|
|
|
|
|
|
|
if( wrote == 0 || oserr != noErr) |
1065
|
|
|
|
|
|
|
break; |
1066
|
|
|
|
|
|
|
amt -= wrote; |
1067
|
|
|
|
|
|
|
pBuf = &((char*)pBuf)[wrote]; |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
if( oserr != noErr || amt>wrote ){ |
1070
|
|
|
|
|
|
|
return SQLITE_FULL; |
1071
|
|
|
|
|
|
|
} |
1072
|
|
|
|
|
|
|
return SQLITE_OK; |
1073
|
|
|
|
|
|
|
#endif |
1074
|
|
|
|
|
|
|
} |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
/* |
1077
|
|
|
|
|
|
|
** Move the read/write pointer in a file. |
1078
|
|
|
|
|
|
|
*/ |
1079
|
836
|
|
|
|
|
|
int sqliteOsSeek(OsFile *id, sql_off_t offset){ |
1080
|
|
|
|
|
|
|
SEEK(offset/1024 + 1); |
1081
|
|
|
|
|
|
|
#if OS_UNIX |
1082
|
836
|
|
|
|
|
|
lseek(id->fd, offset, SEEK_SET); |
1083
|
836
|
|
|
|
|
|
return SQLITE_OK; |
1084
|
|
|
|
|
|
|
#endif |
1085
|
|
|
|
|
|
|
#if OS_WIN |
1086
|
|
|
|
|
|
|
{ |
1087
|
|
|
|
|
|
|
LONG upperBits = offset>>32; |
1088
|
|
|
|
|
|
|
LONG lowerBits = offset & 0xffffffff; |
1089
|
|
|
|
|
|
|
DWORD rc; |
1090
|
|
|
|
|
|
|
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); |
1091
|
|
|
|
|
|
|
/* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */ |
1092
|
|
|
|
|
|
|
} |
1093
|
|
|
|
|
|
|
return SQLITE_OK; |
1094
|
|
|
|
|
|
|
#endif |
1095
|
|
|
|
|
|
|
#if OS_MAC |
1096
|
|
|
|
|
|
|
{ |
1097
|
|
|
|
|
|
|
sql_off_t curSize; |
1098
|
|
|
|
|
|
|
if( sqliteOsFileSize(id, &curSize) != SQLITE_OK ){ |
1099
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
if( offset >= curSize ){ |
1102
|
|
|
|
|
|
|
if( sqliteOsTruncate(id, offset+1) != SQLITE_OK ){ |
1103
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
} |
1106
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
1107
|
|
|
|
|
|
|
if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){ |
1108
|
|
|
|
|
|
|
# else |
1109
|
|
|
|
|
|
|
if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){ |
1110
|
|
|
|
|
|
|
# endif |
1111
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1112
|
|
|
|
|
|
|
}else{ |
1113
|
|
|
|
|
|
|
return SQLITE_OK; |
1114
|
|
|
|
|
|
|
} |
1115
|
|
|
|
|
|
|
} |
1116
|
|
|
|
|
|
|
#endif |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
/* |
1120
|
|
|
|
|
|
|
** Make sure all writes to a particular file are committed to disk. |
1121
|
|
|
|
|
|
|
** |
1122
|
|
|
|
|
|
|
** Under Unix, also make sure that the directory entry for the file |
1123
|
|
|
|
|
|
|
** has been created by fsync-ing the directory that contains the file. |
1124
|
|
|
|
|
|
|
** If we do not do this and we encounter a power failure, the directory |
1125
|
|
|
|
|
|
|
** entry for the journal might not exist after we reboot. The next |
1126
|
|
|
|
|
|
|
** SQLite to access the file will not know that the journal exists (because |
1127
|
|
|
|
|
|
|
** the directory entry for the journal was never created) and the transaction |
1128
|
|
|
|
|
|
|
** will not roll back - possibly leading to database corruption. |
1129
|
|
|
|
|
|
|
*/ |
1130
|
136
|
|
|
|
|
|
int sqliteOsSync(OsFile *id){ |
1131
|
|
|
|
|
|
|
#if OS_UNIX |
1132
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1133
|
|
|
|
|
|
|
TRACE2("SYNC %-3d\n", id->fd); |
1134
|
136
|
50
|
|
|
|
|
if( fsync(id->fd) ){ |
1135
|
0
|
|
|
|
|
|
return SQLITE_IOERR; |
1136
|
|
|
|
|
|
|
}else{ |
1137
|
136
|
100
|
|
|
|
|
if( id->dirfd>=0 ){ |
1138
|
|
|
|
|
|
|
TRACE2("DIRSYNC %-3d\n", id->dirfd); |
1139
|
68
|
|
|
|
|
|
fsync(id->dirfd); |
1140
|
68
|
|
|
|
|
|
close(id->dirfd); /* Only need to sync once, so close the directory */ |
1141
|
68
|
|
|
|
|
|
id->dirfd = -1; /* when we are done. */ |
1142
|
|
|
|
|
|
|
} |
1143
|
136
|
|
|
|
|
|
return SQLITE_OK; |
1144
|
|
|
|
|
|
|
} |
1145
|
|
|
|
|
|
|
#endif |
1146
|
|
|
|
|
|
|
#if OS_WIN |
1147
|
|
|
|
|
|
|
if( FlushFileBuffers(id->h) ){ |
1148
|
|
|
|
|
|
|
return SQLITE_OK; |
1149
|
|
|
|
|
|
|
}else{ |
1150
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
#endif |
1153
|
|
|
|
|
|
|
#if OS_MAC |
1154
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
1155
|
|
|
|
|
|
|
if( FSFlushFork(id->refNum) != noErr ){ |
1156
|
|
|
|
|
|
|
# else |
1157
|
|
|
|
|
|
|
ParamBlockRec params; |
1158
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(ParamBlockRec)); |
1159
|
|
|
|
|
|
|
params.ioParam.ioRefNum = id->refNum; |
1160
|
|
|
|
|
|
|
if( PBFlushFileSync(¶ms) != noErr ){ |
1161
|
|
|
|
|
|
|
# endif |
1162
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1163
|
|
|
|
|
|
|
}else{ |
1164
|
|
|
|
|
|
|
return SQLITE_OK; |
1165
|
|
|
|
|
|
|
} |
1166
|
|
|
|
|
|
|
#endif |
1167
|
|
|
|
|
|
|
} |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
/* |
1170
|
|
|
|
|
|
|
** Truncate an open file to a specified size |
1171
|
|
|
|
|
|
|
*/ |
1172
|
3
|
|
|
|
|
|
int sqliteOsTruncate(OsFile *id, sql_off_t nByte){ |
1173
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1174
|
|
|
|
|
|
|
#if OS_UNIX |
1175
|
3
|
50
|
|
|
|
|
return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; |
1176
|
|
|
|
|
|
|
#endif |
1177
|
|
|
|
|
|
|
#if OS_WIN |
1178
|
|
|
|
|
|
|
{ |
1179
|
|
|
|
|
|
|
LONG upperBits = nByte>>32; |
1180
|
|
|
|
|
|
|
SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN); |
1181
|
|
|
|
|
|
|
SetEndOfFile(id->h); |
1182
|
|
|
|
|
|
|
} |
1183
|
|
|
|
|
|
|
return SQLITE_OK; |
1184
|
|
|
|
|
|
|
#endif |
1185
|
|
|
|
|
|
|
#if OS_MAC |
1186
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
1187
|
|
|
|
|
|
|
if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){ |
1188
|
|
|
|
|
|
|
# else |
1189
|
|
|
|
|
|
|
if( SetEOF(id->refNum, nByte) != noErr ){ |
1190
|
|
|
|
|
|
|
# endif |
1191
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1192
|
|
|
|
|
|
|
}else{ |
1193
|
|
|
|
|
|
|
return SQLITE_OK; |
1194
|
|
|
|
|
|
|
} |
1195
|
|
|
|
|
|
|
#endif |
1196
|
|
|
|
|
|
|
} |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
/* |
1199
|
|
|
|
|
|
|
** Determine the current size of a file in bytes |
1200
|
|
|
|
|
|
|
*/ |
1201
|
262
|
|
|
|
|
|
int sqliteOsFileSize(OsFile *id, sql_off_t *pSize){ |
1202
|
|
|
|
|
|
|
#if OS_UNIX |
1203
|
|
|
|
|
|
|
struct stat buf; |
1204
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1205
|
262
|
50
|
|
|
|
|
if( fstat(id->fd, &buf)!=0 ){ |
1206
|
0
|
|
|
|
|
|
return SQLITE_IOERR; |
1207
|
|
|
|
|
|
|
} |
1208
|
262
|
|
|
|
|
|
*pSize = buf.st_size; |
1209
|
262
|
|
|
|
|
|
return SQLITE_OK; |
1210
|
|
|
|
|
|
|
#endif |
1211
|
|
|
|
|
|
|
#if OS_WIN |
1212
|
|
|
|
|
|
|
DWORD upperBits, lowerBits; |
1213
|
|
|
|
|
|
|
SimulateIOError(SQLITE_IOERR); |
1214
|
|
|
|
|
|
|
lowerBits = GetFileSize(id->h, &upperBits); |
1215
|
|
|
|
|
|
|
*pSize = (((sql_off_t)upperBits)<<32) + lowerBits; |
1216
|
|
|
|
|
|
|
return SQLITE_OK; |
1217
|
|
|
|
|
|
|
#endif |
1218
|
|
|
|
|
|
|
#if OS_MAC |
1219
|
|
|
|
|
|
|
# ifdef _LARGE_FILE |
1220
|
|
|
|
|
|
|
if( FSGetForkSize(id->refNum, pSize) != noErr){ |
1221
|
|
|
|
|
|
|
# else |
1222
|
|
|
|
|
|
|
if( GetEOF(id->refNum, pSize) != noErr ){ |
1223
|
|
|
|
|
|
|
# endif |
1224
|
|
|
|
|
|
|
return SQLITE_IOERR; |
1225
|
|
|
|
|
|
|
}else{ |
1226
|
|
|
|
|
|
|
return SQLITE_OK; |
1227
|
|
|
|
|
|
|
} |
1228
|
|
|
|
|
|
|
#endif |
1229
|
|
|
|
|
|
|
} |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
#if OS_WIN |
1232
|
|
|
|
|
|
|
/* |
1233
|
|
|
|
|
|
|
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP. |
1234
|
|
|
|
|
|
|
** Return false (zero) for Win95, Win98, or WinME. |
1235
|
|
|
|
|
|
|
** |
1236
|
|
|
|
|
|
|
** Here is an interesting observation: Win95, Win98, and WinME lack |
1237
|
|
|
|
|
|
|
** the LockFileEx() API. But we can still statically link against that |
1238
|
|
|
|
|
|
|
** API as long as we don't call it win running Win95/98/ME. A call to |
1239
|
|
|
|
|
|
|
** this routine is used to determine if the host is Win95/98/ME or |
1240
|
|
|
|
|
|
|
** WinNT/2K/XP so that we will know whether or not we can safely call |
1241
|
|
|
|
|
|
|
** the LockFileEx() API. |
1242
|
|
|
|
|
|
|
*/ |
1243
|
|
|
|
|
|
|
int isNT(void){ |
1244
|
|
|
|
|
|
|
static int osType = 0; /* 0=unknown 1=win95 2=winNT */ |
1245
|
|
|
|
|
|
|
if( osType==0 ){ |
1246
|
|
|
|
|
|
|
OSVERSIONINFO sInfo; |
1247
|
|
|
|
|
|
|
sInfo.dwOSVersionInfoSize = sizeof(sInfo); |
1248
|
|
|
|
|
|
|
GetVersionEx(&sInfo); |
1249
|
|
|
|
|
|
|
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; |
1250
|
|
|
|
|
|
|
} |
1251
|
|
|
|
|
|
|
return osType==2; |
1252
|
|
|
|
|
|
|
} |
1253
|
|
|
|
|
|
|
#endif |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
/* |
1256
|
|
|
|
|
|
|
** Windows file locking notes: [similar issues apply to MacOS] |
1257
|
|
|
|
|
|
|
** |
1258
|
|
|
|
|
|
|
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because |
1259
|
|
|
|
|
|
|
** those functions are not available. So we use only LockFile() and |
1260
|
|
|
|
|
|
|
** UnlockFile(). |
1261
|
|
|
|
|
|
|
** |
1262
|
|
|
|
|
|
|
** LockFile() prevents not just writing but also reading by other processes. |
1263
|
|
|
|
|
|
|
** (This is a design error on the part of Windows, but there is nothing |
1264
|
|
|
|
|
|
|
** we can do about that.) So the region used for locking is at the |
1265
|
|
|
|
|
|
|
** end of the file where it is unlikely to ever interfere with an |
1266
|
|
|
|
|
|
|
** actual read attempt. |
1267
|
|
|
|
|
|
|
** |
1268
|
|
|
|
|
|
|
** A database read lock is obtained by locking a single randomly-chosen |
1269
|
|
|
|
|
|
|
** byte out of a specific range of bytes. The lock byte is obtained at |
1270
|
|
|
|
|
|
|
** random so two separate readers can probably access the file at the |
1271
|
|
|
|
|
|
|
** same time, unless they are unlucky and choose the same lock byte. |
1272
|
|
|
|
|
|
|
** A database write lock is obtained by locking all bytes in the range. |
1273
|
|
|
|
|
|
|
** There can only be one writer. |
1274
|
|
|
|
|
|
|
** |
1275
|
|
|
|
|
|
|
** A lock is obtained on the first byte of the lock range before acquiring |
1276
|
|
|
|
|
|
|
** either a read lock or a write lock. This prevents two processes from |
1277
|
|
|
|
|
|
|
** attempting to get a lock at a same time. The semantics of |
1278
|
|
|
|
|
|
|
** sqliteOsReadLock() require that if there is already a write lock, that |
1279
|
|
|
|
|
|
|
** lock is converted into a read lock atomically. The lock on the first |
1280
|
|
|
|
|
|
|
** byte allows us to drop the old write lock and get the read lock without |
1281
|
|
|
|
|
|
|
** another process jumping into the middle and messing us up. The same |
1282
|
|
|
|
|
|
|
** argument applies to sqliteOsWriteLock(). |
1283
|
|
|
|
|
|
|
** |
1284
|
|
|
|
|
|
|
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available, |
1285
|
|
|
|
|
|
|
** which means we can use reader/writer locks. When reader writer locks |
1286
|
|
|
|
|
|
|
** are used, the lock is placed on the same range of bytes that is used |
1287
|
|
|
|
|
|
|
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme |
1288
|
|
|
|
|
|
|
** will support two or more Win95 readers or two or more WinNT readers. |
1289
|
|
|
|
|
|
|
** But a single Win95 reader will lock out all WinNT readers and a single |
1290
|
|
|
|
|
|
|
** WinNT reader will lock out all other Win95 readers. |
1291
|
|
|
|
|
|
|
** |
1292
|
|
|
|
|
|
|
** Note: On MacOS we use the resource fork for locking. |
1293
|
|
|
|
|
|
|
** |
1294
|
|
|
|
|
|
|
** The following #defines specify the range of bytes used for locking. |
1295
|
|
|
|
|
|
|
** N_LOCKBYTE is the number of bytes available for doing the locking. |
1296
|
|
|
|
|
|
|
** The first byte used to hold the lock while the lock is changing does |
1297
|
|
|
|
|
|
|
** not count toward this number. FIRST_LOCKBYTE is the address of |
1298
|
|
|
|
|
|
|
** the first byte in the range of bytes used for locking. |
1299
|
|
|
|
|
|
|
*/ |
1300
|
|
|
|
|
|
|
#define N_LOCKBYTE 10239 |
1301
|
|
|
|
|
|
|
#if OS_MAC |
1302
|
|
|
|
|
|
|
# define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE) |
1303
|
|
|
|
|
|
|
#else |
1304
|
|
|
|
|
|
|
# define FIRST_LOCKBYTE (0xffffffff - N_LOCKBYTE) |
1305
|
|
|
|
|
|
|
#endif |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
/* |
1308
|
|
|
|
|
|
|
** Change the status of the lock on the file "id" to be a readlock. |
1309
|
|
|
|
|
|
|
** If the file was write locked, then this reduces the lock to a read. |
1310
|
|
|
|
|
|
|
** If the file was read locked, then this acquires a new read lock. |
1311
|
|
|
|
|
|
|
** |
1312
|
|
|
|
|
|
|
** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this |
1313
|
|
|
|
|
|
|
** library was compiled with large file support (LFS) but LFS is not |
1314
|
|
|
|
|
|
|
** available on the host, then an SQLITE_NOLFS is returned. |
1315
|
|
|
|
|
|
|
*/ |
1316
|
415
|
|
|
|
|
|
int sqliteOsReadLock(OsFile *id){ |
1317
|
|
|
|
|
|
|
#if OS_UNIX |
1318
|
|
|
|
|
|
|
int rc; |
1319
|
415
|
|
|
|
|
|
sqliteOsEnterMutex(); |
1320
|
415
|
50
|
|
|
|
|
if( id->pLock->cnt>0 ){ |
1321
|
0
|
0
|
|
|
|
|
if( !id->locked ){ |
1322
|
0
|
|
|
|
|
|
id->pLock->cnt++; |
1323
|
0
|
|
|
|
|
|
id->locked = 1; |
1324
|
0
|
|
|
|
|
|
id->pOpen->nLock++; |
1325
|
|
|
|
|
|
|
} |
1326
|
0
|
|
|
|
|
|
rc = SQLITE_OK; |
1327
|
830
|
100
|
|
|
|
|
}else if( id->locked || id->pLock->cnt==0 ){ |
|
|
50
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
struct flock lock; |
1329
|
|
|
|
|
|
|
int s; |
1330
|
415
|
|
|
|
|
|
lock.l_type = F_RDLCK; |
1331
|
415
|
|
|
|
|
|
lock.l_whence = SEEK_SET; |
1332
|
415
|
|
|
|
|
|
lock.l_start = lock.l_len = 0L; |
1333
|
415
|
|
|
|
|
|
s = fcntl(id->fd, F_SETLK, &lock); |
1334
|
415
|
50
|
|
|
|
|
if( s!=0 ){ |
1335
|
0
|
0
|
|
|
|
|
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; |
1336
|
|
|
|
|
|
|
}else{ |
1337
|
415
|
|
|
|
|
|
rc = SQLITE_OK; |
1338
|
415
|
100
|
|
|
|
|
if( !id->locked ){ |
1339
|
259
|
|
|
|
|
|
id->pOpen->nLock++; |
1340
|
259
|
|
|
|
|
|
id->locked = 1; |
1341
|
|
|
|
|
|
|
} |
1342
|
415
|
|
|
|
|
|
id->pLock->cnt = 1; |
1343
|
|
|
|
|
|
|
} |
1344
|
|
|
|
|
|
|
}else{ |
1345
|
0
|
|
|
|
|
|
rc = SQLITE_BUSY; |
1346
|
|
|
|
|
|
|
} |
1347
|
415
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
1348
|
415
|
|
|
|
|
|
return rc; |
1349
|
|
|
|
|
|
|
#endif |
1350
|
|
|
|
|
|
|
#if OS_WIN |
1351
|
|
|
|
|
|
|
int rc; |
1352
|
|
|
|
|
|
|
if( id->locked>0 ){ |
1353
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1354
|
|
|
|
|
|
|
}else{ |
1355
|
|
|
|
|
|
|
int lk; |
1356
|
|
|
|
|
|
|
int res; |
1357
|
|
|
|
|
|
|
int cnt = 100; |
1358
|
|
|
|
|
|
|
sqliteRandomness(sizeof(lk), &lk); |
1359
|
|
|
|
|
|
|
lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1; |
1360
|
|
|
|
|
|
|
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){ |
1361
|
|
|
|
|
|
|
Sleep(1); |
1362
|
|
|
|
|
|
|
} |
1363
|
|
|
|
|
|
|
if( res ){ |
1364
|
|
|
|
|
|
|
UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); |
1365
|
|
|
|
|
|
|
if( isNT() ){ |
1366
|
|
|
|
|
|
|
OVERLAPPED ovlp; |
1367
|
|
|
|
|
|
|
ovlp.Offset = FIRST_LOCKBYTE+1; |
1368
|
|
|
|
|
|
|
ovlp.OffsetHigh = 0; |
1369
|
|
|
|
|
|
|
ovlp.hEvent = 0; |
1370
|
|
|
|
|
|
|
res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, |
1371
|
|
|
|
|
|
|
0, N_LOCKBYTE, 0, &ovlp); |
1372
|
|
|
|
|
|
|
}else{ |
1373
|
|
|
|
|
|
|
res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0); |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0); |
1376
|
|
|
|
|
|
|
} |
1377
|
|
|
|
|
|
|
if( res ){ |
1378
|
|
|
|
|
|
|
id->locked = lk; |
1379
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1380
|
|
|
|
|
|
|
}else{ |
1381
|
|
|
|
|
|
|
rc = SQLITE_BUSY; |
1382
|
|
|
|
|
|
|
} |
1383
|
|
|
|
|
|
|
} |
1384
|
|
|
|
|
|
|
return rc; |
1385
|
|
|
|
|
|
|
#endif |
1386
|
|
|
|
|
|
|
#if OS_MAC |
1387
|
|
|
|
|
|
|
int rc; |
1388
|
|
|
|
|
|
|
if( id->locked>0 || id->refNumRF == -1 ){ |
1389
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1390
|
|
|
|
|
|
|
}else{ |
1391
|
|
|
|
|
|
|
int lk; |
1392
|
|
|
|
|
|
|
OSErr res; |
1393
|
|
|
|
|
|
|
int cnt = 5; |
1394
|
|
|
|
|
|
|
ParamBlockRec params; |
1395
|
|
|
|
|
|
|
sqliteRandomness(sizeof(lk), &lk); |
1396
|
|
|
|
|
|
|
lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1; |
1397
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(params)); |
1398
|
|
|
|
|
|
|
params.ioParam.ioRefNum = id->refNumRF; |
1399
|
|
|
|
|
|
|
params.ioParam.ioPosMode = fsFromStart; |
1400
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE; |
1401
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1402
|
|
|
|
|
|
|
while( cnt-->0 && (res = PBLockRangeSync(¶ms))!=noErr ){ |
1403
|
|
|
|
|
|
|
UInt32 finalTicks; |
1404
|
|
|
|
|
|
|
Delay(1, &finalTicks); /* 1/60 sec */ |
1405
|
|
|
|
|
|
|
} |
1406
|
|
|
|
|
|
|
if( res == noErr ){ |
1407
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1; |
1408
|
|
|
|
|
|
|
params.ioParam.ioReqCount = N_LOCKBYTE; |
1409
|
|
|
|
|
|
|
PBUnlockRangeSync(¶ms); |
1410
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk; |
1411
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1412
|
|
|
|
|
|
|
res = PBLockRangeSync(¶ms); |
1413
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE; |
1414
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1415
|
|
|
|
|
|
|
PBUnlockRangeSync(¶ms); |
1416
|
|
|
|
|
|
|
} |
1417
|
|
|
|
|
|
|
if( res == noErr ){ |
1418
|
|
|
|
|
|
|
id->locked = lk; |
1419
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1420
|
|
|
|
|
|
|
}else{ |
1421
|
|
|
|
|
|
|
rc = SQLITE_BUSY; |
1422
|
|
|
|
|
|
|
} |
1423
|
|
|
|
|
|
|
} |
1424
|
|
|
|
|
|
|
return rc; |
1425
|
|
|
|
|
|
|
#endif |
1426
|
|
|
|
|
|
|
} |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
/* |
1429
|
|
|
|
|
|
|
** Change the lock status to be an exclusive or write lock. Return |
1430
|
|
|
|
|
|
|
** SQLITE_OK on success and SQLITE_BUSY on a failure. If this |
1431
|
|
|
|
|
|
|
** library was compiled with large file support (LFS) but LFS is not |
1432
|
|
|
|
|
|
|
** available on the host, then an SQLITE_NOLFS is returned. |
1433
|
|
|
|
|
|
|
*/ |
1434
|
156
|
|
|
|
|
|
int sqliteOsWriteLock(OsFile *id){ |
1435
|
|
|
|
|
|
|
#if OS_UNIX |
1436
|
|
|
|
|
|
|
int rc; |
1437
|
156
|
|
|
|
|
|
sqliteOsEnterMutex(); |
1438
|
312
|
50
|
|
|
|
|
if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){ |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
struct flock lock; |
1440
|
|
|
|
|
|
|
int s; |
1441
|
156
|
|
|
|
|
|
lock.l_type = F_WRLCK; |
1442
|
156
|
|
|
|
|
|
lock.l_whence = SEEK_SET; |
1443
|
156
|
|
|
|
|
|
lock.l_start = lock.l_len = 0L; |
1444
|
156
|
|
|
|
|
|
s = fcntl(id->fd, F_SETLK, &lock); |
1445
|
156
|
50
|
|
|
|
|
if( s!=0 ){ |
1446
|
0
|
0
|
|
|
|
|
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; |
1447
|
|
|
|
|
|
|
}else{ |
1448
|
156
|
|
|
|
|
|
rc = SQLITE_OK; |
1449
|
156
|
50
|
|
|
|
|
if( !id->locked ){ |
1450
|
0
|
|
|
|
|
|
id->pOpen->nLock++; |
1451
|
0
|
|
|
|
|
|
id->locked = 1; |
1452
|
|
|
|
|
|
|
} |
1453
|
156
|
|
|
|
|
|
id->pLock->cnt = -1; |
1454
|
|
|
|
|
|
|
} |
1455
|
|
|
|
|
|
|
}else{ |
1456
|
0
|
|
|
|
|
|
rc = SQLITE_BUSY; |
1457
|
|
|
|
|
|
|
} |
1458
|
156
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
1459
|
156
|
|
|
|
|
|
return rc; |
1460
|
|
|
|
|
|
|
#endif |
1461
|
|
|
|
|
|
|
#if OS_WIN |
1462
|
|
|
|
|
|
|
int rc; |
1463
|
|
|
|
|
|
|
if( id->locked<0 ){ |
1464
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1465
|
|
|
|
|
|
|
}else{ |
1466
|
|
|
|
|
|
|
int res; |
1467
|
|
|
|
|
|
|
int cnt = 100; |
1468
|
|
|
|
|
|
|
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){ |
1469
|
|
|
|
|
|
|
Sleep(1); |
1470
|
|
|
|
|
|
|
} |
1471
|
|
|
|
|
|
|
if( res ){ |
1472
|
|
|
|
|
|
|
if( id->locked>0 ){ |
1473
|
|
|
|
|
|
|
if( isNT() ){ |
1474
|
|
|
|
|
|
|
UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); |
1475
|
|
|
|
|
|
|
}else{ |
1476
|
|
|
|
|
|
|
res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0); |
1477
|
|
|
|
|
|
|
} |
1478
|
|
|
|
|
|
|
} |
1479
|
|
|
|
|
|
|
if( res ){ |
1480
|
|
|
|
|
|
|
res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); |
1481
|
|
|
|
|
|
|
}else{ |
1482
|
|
|
|
|
|
|
res = 0; |
1483
|
|
|
|
|
|
|
} |
1484
|
|
|
|
|
|
|
UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0); |
1485
|
|
|
|
|
|
|
} |
1486
|
|
|
|
|
|
|
if( res ){ |
1487
|
|
|
|
|
|
|
id->locked = -1; |
1488
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1489
|
|
|
|
|
|
|
}else{ |
1490
|
|
|
|
|
|
|
rc = SQLITE_BUSY; |
1491
|
|
|
|
|
|
|
} |
1492
|
|
|
|
|
|
|
} |
1493
|
|
|
|
|
|
|
return rc; |
1494
|
|
|
|
|
|
|
#endif |
1495
|
|
|
|
|
|
|
#if OS_MAC |
1496
|
|
|
|
|
|
|
int rc; |
1497
|
|
|
|
|
|
|
if( id->locked<0 || id->refNumRF == -1 ){ |
1498
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1499
|
|
|
|
|
|
|
}else{ |
1500
|
|
|
|
|
|
|
OSErr res; |
1501
|
|
|
|
|
|
|
int cnt = 5; |
1502
|
|
|
|
|
|
|
ParamBlockRec params; |
1503
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(params)); |
1504
|
|
|
|
|
|
|
params.ioParam.ioRefNum = id->refNumRF; |
1505
|
|
|
|
|
|
|
params.ioParam.ioPosMode = fsFromStart; |
1506
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE; |
1507
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1508
|
|
|
|
|
|
|
while( cnt-->0 && (res = PBLockRangeSync(¶ms))!=noErr ){ |
1509
|
|
|
|
|
|
|
UInt32 finalTicks; |
1510
|
|
|
|
|
|
|
Delay(1, &finalTicks); /* 1/60 sec */ |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
if( res == noErr ){ |
1513
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked; |
1514
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1515
|
|
|
|
|
|
|
if( id->locked==0 |
1516
|
|
|
|
|
|
|
|| PBUnlockRangeSync(¶ms)==noErr ){ |
1517
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1; |
1518
|
|
|
|
|
|
|
params.ioParam.ioReqCount = N_LOCKBYTE; |
1519
|
|
|
|
|
|
|
res = PBLockRangeSync(¶ms); |
1520
|
|
|
|
|
|
|
}else{ |
1521
|
|
|
|
|
|
|
res = afpRangeNotLocked; |
1522
|
|
|
|
|
|
|
} |
1523
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE; |
1524
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1525
|
|
|
|
|
|
|
PBUnlockRangeSync(¶ms); |
1526
|
|
|
|
|
|
|
} |
1527
|
|
|
|
|
|
|
if( res == noErr ){ |
1528
|
|
|
|
|
|
|
id->locked = -1; |
1529
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1530
|
|
|
|
|
|
|
}else{ |
1531
|
|
|
|
|
|
|
rc = SQLITE_BUSY; |
1532
|
|
|
|
|
|
|
} |
1533
|
|
|
|
|
|
|
} |
1534
|
|
|
|
|
|
|
return rc; |
1535
|
|
|
|
|
|
|
#endif |
1536
|
|
|
|
|
|
|
} |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
/* |
1539
|
|
|
|
|
|
|
** Unlock the given file descriptor. If the file descriptor was |
1540
|
|
|
|
|
|
|
** not previously locked, then this routine is a no-op. If this |
1541
|
|
|
|
|
|
|
** library was compiled with large file support (LFS) but LFS is not |
1542
|
|
|
|
|
|
|
** available on the host, then an SQLITE_NOLFS is returned. |
1543
|
|
|
|
|
|
|
*/ |
1544
|
410
|
|
|
|
|
|
int sqliteOsUnlock(OsFile *id){ |
1545
|
|
|
|
|
|
|
#if OS_UNIX |
1546
|
|
|
|
|
|
|
int rc; |
1547
|
410
|
100
|
|
|
|
|
if( !id->locked ) return SQLITE_OK; |
1548
|
259
|
|
|
|
|
|
sqliteOsEnterMutex(); |
1549
|
|
|
|
|
|
|
assert( id->pLock->cnt!=0 ); |
1550
|
259
|
50
|
|
|
|
|
if( id->pLock->cnt>1 ){ |
1551
|
0
|
|
|
|
|
|
id->pLock->cnt--; |
1552
|
0
|
|
|
|
|
|
rc = SQLITE_OK; |
1553
|
|
|
|
|
|
|
}else{ |
1554
|
|
|
|
|
|
|
struct flock lock; |
1555
|
|
|
|
|
|
|
int s; |
1556
|
259
|
|
|
|
|
|
lock.l_type = F_UNLCK; |
1557
|
259
|
|
|
|
|
|
lock.l_whence = SEEK_SET; |
1558
|
259
|
|
|
|
|
|
lock.l_start = lock.l_len = 0L; |
1559
|
259
|
|
|
|
|
|
s = fcntl(id->fd, F_SETLK, &lock); |
1560
|
259
|
50
|
|
|
|
|
if( s!=0 ){ |
1561
|
0
|
0
|
|
|
|
|
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; |
1562
|
|
|
|
|
|
|
}else{ |
1563
|
259
|
|
|
|
|
|
rc = SQLITE_OK; |
1564
|
259
|
|
|
|
|
|
id->pLock->cnt = 0; |
1565
|
|
|
|
|
|
|
} |
1566
|
|
|
|
|
|
|
} |
1567
|
259
|
50
|
|
|
|
|
if( rc==SQLITE_OK ){ |
1568
|
|
|
|
|
|
|
/* Decrement the count of locks against this same file. When the |
1569
|
|
|
|
|
|
|
** count reaches zero, close any other file descriptors whose close |
1570
|
|
|
|
|
|
|
** was deferred because of outstanding locks. |
1571
|
|
|
|
|
|
|
*/ |
1572
|
259
|
|
|
|
|
|
struct openCnt *pOpen = id->pOpen; |
1573
|
259
|
|
|
|
|
|
pOpen->nLock--; |
1574
|
|
|
|
|
|
|
assert( pOpen->nLock>=0 ); |
1575
|
259
|
50
|
|
|
|
|
if( pOpen->nLock==0 && pOpen->nPending>0 ){ |
|
|
50
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
int i; |
1577
|
0
|
0
|
|
|
|
|
for(i=0; inPending; i++){ |
1578
|
0
|
|
|
|
|
|
close(pOpen->aPending[i]); |
1579
|
|
|
|
|
|
|
} |
1580
|
0
|
|
|
|
|
|
sqliteFree(pOpen->aPending); |
1581
|
0
|
|
|
|
|
|
pOpen->nPending = 0; |
1582
|
0
|
|
|
|
|
|
pOpen->aPending = 0; |
1583
|
|
|
|
|
|
|
} |
1584
|
|
|
|
|
|
|
} |
1585
|
259
|
|
|
|
|
|
sqliteOsLeaveMutex(); |
1586
|
259
|
|
|
|
|
|
id->locked = 0; |
1587
|
259
|
|
|
|
|
|
return rc; |
1588
|
|
|
|
|
|
|
#endif |
1589
|
|
|
|
|
|
|
#if OS_WIN |
1590
|
|
|
|
|
|
|
int rc; |
1591
|
|
|
|
|
|
|
if( id->locked==0 ){ |
1592
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1593
|
|
|
|
|
|
|
}else if( isNT() || id->locked<0 ){ |
1594
|
|
|
|
|
|
|
UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); |
1595
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1596
|
|
|
|
|
|
|
id->locked = 0; |
1597
|
|
|
|
|
|
|
}else{ |
1598
|
|
|
|
|
|
|
UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0); |
1599
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1600
|
|
|
|
|
|
|
id->locked = 0; |
1601
|
|
|
|
|
|
|
} |
1602
|
|
|
|
|
|
|
return rc; |
1603
|
|
|
|
|
|
|
#endif |
1604
|
|
|
|
|
|
|
#if OS_MAC |
1605
|
|
|
|
|
|
|
int rc; |
1606
|
|
|
|
|
|
|
ParamBlockRec params; |
1607
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(params)); |
1608
|
|
|
|
|
|
|
params.ioParam.ioRefNum = id->refNumRF; |
1609
|
|
|
|
|
|
|
params.ioParam.ioPosMode = fsFromStart; |
1610
|
|
|
|
|
|
|
if( id->locked==0 || id->refNumRF == -1 ){ |
1611
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1612
|
|
|
|
|
|
|
}else if( id->locked<0 ){ |
1613
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1; |
1614
|
|
|
|
|
|
|
params.ioParam.ioReqCount = N_LOCKBYTE; |
1615
|
|
|
|
|
|
|
PBUnlockRangeSync(¶ms); |
1616
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1617
|
|
|
|
|
|
|
id->locked = 0; |
1618
|
|
|
|
|
|
|
}else{ |
1619
|
|
|
|
|
|
|
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked; |
1620
|
|
|
|
|
|
|
params.ioParam.ioReqCount = 1; |
1621
|
|
|
|
|
|
|
PBUnlockRangeSync(¶ms); |
1622
|
|
|
|
|
|
|
rc = SQLITE_OK; |
1623
|
|
|
|
|
|
|
id->locked = 0; |
1624
|
|
|
|
|
|
|
} |
1625
|
|
|
|
|
|
|
return rc; |
1626
|
|
|
|
|
|
|
#endif |
1627
|
|
|
|
|
|
|
} |
1628
|
|
|
|
|
|
|
|
1629
|
|
|
|
|
|
|
/* |
1630
|
|
|
|
|
|
|
** Get information to seed the random number generator. The seed |
1631
|
|
|
|
|
|
|
** is written into the buffer zBuf[256]. The calling function must |
1632
|
|
|
|
|
|
|
** supply a sufficiently large buffer. |
1633
|
|
|
|
|
|
|
*/ |
1634
|
21
|
|
|
|
|
|
int sqliteOsRandomSeed(char *zBuf){ |
1635
|
|
|
|
|
|
|
/* We have to initialize zBuf to prevent valgrind from reporting |
1636
|
|
|
|
|
|
|
** errors. The reports issued by valgrind are incorrect - we would |
1637
|
|
|
|
|
|
|
** prefer that the randomness be increased by making use of the |
1638
|
|
|
|
|
|
|
** uninitialized space in zBuf - but valgrind errors tend to worry |
1639
|
|
|
|
|
|
|
** some users. Rather than argue, it seems easier just to initialize |
1640
|
|
|
|
|
|
|
** the whole array and silence valgrind, even if that means less randomness |
1641
|
|
|
|
|
|
|
** in the random seed. |
1642
|
|
|
|
|
|
|
** |
1643
|
|
|
|
|
|
|
** When testing, initializing zBuf[] to zero is all we do. That means |
1644
|
|
|
|
|
|
|
** that we always use the same random number sequence.* This makes the |
1645
|
|
|
|
|
|
|
** tests repeatable. |
1646
|
|
|
|
|
|
|
*/ |
1647
|
21
|
|
|
|
|
|
memset(zBuf, 0, 256); |
1648
|
|
|
|
|
|
|
#if OS_UNIX && !defined(SQLITE_TEST) |
1649
|
|
|
|
|
|
|
{ |
1650
|
|
|
|
|
|
|
int pid; |
1651
|
21
|
|
|
|
|
|
time((time_t*)zBuf); |
1652
|
21
|
|
|
|
|
|
pid = getpid(); |
1653
|
21
|
|
|
|
|
|
memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); |
1654
|
|
|
|
|
|
|
} |
1655
|
|
|
|
|
|
|
#endif |
1656
|
|
|
|
|
|
|
#if OS_WIN && !defined(SQLITE_TEST) |
1657
|
|
|
|
|
|
|
GetSystemTime((LPSYSTEMTIME)zBuf); |
1658
|
|
|
|
|
|
|
#endif |
1659
|
|
|
|
|
|
|
#if OS_MAC |
1660
|
|
|
|
|
|
|
{ |
1661
|
|
|
|
|
|
|
int pid; |
1662
|
|
|
|
|
|
|
Microseconds((UnsignedWide*)zBuf); |
1663
|
|
|
|
|
|
|
pid = getpid(); |
1664
|
|
|
|
|
|
|
memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid)); |
1665
|
|
|
|
|
|
|
} |
1666
|
|
|
|
|
|
|
#endif |
1667
|
21
|
|
|
|
|
|
return SQLITE_OK; |
1668
|
|
|
|
|
|
|
} |
1669
|
|
|
|
|
|
|
|
1670
|
|
|
|
|
|
|
/* |
1671
|
|
|
|
|
|
|
** Sleep for a little while. Return the amount of time slept. |
1672
|
|
|
|
|
|
|
*/ |
1673
|
0
|
|
|
|
|
|
int sqliteOsSleep(int ms){ |
1674
|
|
|
|
|
|
|
#if OS_UNIX |
1675
|
|
|
|
|
|
|
#if defined(HAVE_USLEEP) && HAVE_USLEEP |
1676
|
0
|
|
|
|
|
|
usleep(ms*1000); |
1677
|
0
|
|
|
|
|
|
return ms; |
1678
|
|
|
|
|
|
|
#else |
1679
|
|
|
|
|
|
|
sleep((ms+999)/1000); |
1680
|
|
|
|
|
|
|
return 1000*((ms+999)/1000); |
1681
|
|
|
|
|
|
|
#endif |
1682
|
|
|
|
|
|
|
#endif |
1683
|
|
|
|
|
|
|
#if OS_WIN |
1684
|
|
|
|
|
|
|
Sleep(ms); |
1685
|
|
|
|
|
|
|
return ms; |
1686
|
|
|
|
|
|
|
#endif |
1687
|
|
|
|
|
|
|
#if OS_MAC |
1688
|
|
|
|
|
|
|
UInt32 finalTicks; |
1689
|
|
|
|
|
|
|
UInt32 ticks = (((UInt32)ms+16)*3)/50; /* 1/60 sec per tick */ |
1690
|
|
|
|
|
|
|
Delay(ticks, &finalTicks); |
1691
|
|
|
|
|
|
|
return (int)((ticks*50)/3); |
1692
|
|
|
|
|
|
|
#endif |
1693
|
|
|
|
|
|
|
} |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
/* |
1696
|
|
|
|
|
|
|
** Static variables used for thread synchronization |
1697
|
|
|
|
|
|
|
*/ |
1698
|
|
|
|
|
|
|
static int inMutex = 0; |
1699
|
|
|
|
|
|
|
#ifdef SQLITE_UNIX_THREADS |
1700
|
|
|
|
|
|
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
1701
|
|
|
|
|
|
|
#endif |
1702
|
|
|
|
|
|
|
#ifdef SQLITE_W32_THREADS |
1703
|
|
|
|
|
|
|
static CRITICAL_SECTION cs; |
1704
|
|
|
|
|
|
|
#endif |
1705
|
|
|
|
|
|
|
#ifdef SQLITE_MACOS_MULTITASKING |
1706
|
|
|
|
|
|
|
static MPCriticalRegionID criticalRegion; |
1707
|
|
|
|
|
|
|
#endif |
1708
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
/* |
1710
|
|
|
|
|
|
|
** The following pair of routine implement mutual exclusion for |
1711
|
|
|
|
|
|
|
** multi-threaded processes. Only a single thread is allowed to |
1712
|
|
|
|
|
|
|
** executed code that is surrounded by EnterMutex() and LeaveMutex(). |
1713
|
|
|
|
|
|
|
** |
1714
|
|
|
|
|
|
|
** SQLite uses only a single Mutex. There is not much critical |
1715
|
|
|
|
|
|
|
** code and what little there is executes quickly and without blocking. |
1716
|
|
|
|
|
|
|
*/ |
1717
|
1311
|
|
|
|
|
|
void sqliteOsEnterMutex(){ |
1718
|
|
|
|
|
|
|
#ifdef SQLITE_UNIX_THREADS |
1719
|
|
|
|
|
|
|
pthread_mutex_lock(&mutex); |
1720
|
|
|
|
|
|
|
#endif |
1721
|
|
|
|
|
|
|
#ifdef SQLITE_W32_THREADS |
1722
|
|
|
|
|
|
|
static int isInit = 0; |
1723
|
|
|
|
|
|
|
while( !isInit ){ |
1724
|
|
|
|
|
|
|
static long lock = 0; |
1725
|
|
|
|
|
|
|
if( InterlockedIncrement(&lock)==1 ){ |
1726
|
|
|
|
|
|
|
InitializeCriticalSection(&cs); |
1727
|
|
|
|
|
|
|
isInit = 1; |
1728
|
|
|
|
|
|
|
}else{ |
1729
|
|
|
|
|
|
|
Sleep(1); |
1730
|
|
|
|
|
|
|
} |
1731
|
|
|
|
|
|
|
} |
1732
|
|
|
|
|
|
|
EnterCriticalSection(&cs); |
1733
|
|
|
|
|
|
|
#endif |
1734
|
|
|
|
|
|
|
#ifdef SQLITE_MACOS_MULTITASKING |
1735
|
|
|
|
|
|
|
static volatile int notInit = 1; |
1736
|
|
|
|
|
|
|
if( notInit ){ |
1737
|
|
|
|
|
|
|
if( notInit == 2 ) /* as close as you can get to thread safe init */ |
1738
|
|
|
|
|
|
|
MPYield(); |
1739
|
|
|
|
|
|
|
else{ |
1740
|
|
|
|
|
|
|
notInit = 2; |
1741
|
|
|
|
|
|
|
MPCreateCriticalRegion(&criticalRegion); |
1742
|
|
|
|
|
|
|
notInit = 0; |
1743
|
|
|
|
|
|
|
} |
1744
|
|
|
|
|
|
|
} |
1745
|
|
|
|
|
|
|
MPEnterCriticalRegion(criticalRegion, kDurationForever); |
1746
|
|
|
|
|
|
|
#endif |
1747
|
|
|
|
|
|
|
assert( !inMutex ); |
1748
|
1311
|
|
|
|
|
|
inMutex = 1; |
1749
|
1311
|
|
|
|
|
|
} |
1750
|
1311
|
|
|
|
|
|
void sqliteOsLeaveMutex(){ |
1751
|
|
|
|
|
|
|
assert( inMutex ); |
1752
|
1311
|
|
|
|
|
|
inMutex = 0; |
1753
|
|
|
|
|
|
|
#ifdef SQLITE_UNIX_THREADS |
1754
|
|
|
|
|
|
|
pthread_mutex_unlock(&mutex); |
1755
|
|
|
|
|
|
|
#endif |
1756
|
|
|
|
|
|
|
#ifdef SQLITE_W32_THREADS |
1757
|
|
|
|
|
|
|
LeaveCriticalSection(&cs); |
1758
|
|
|
|
|
|
|
#endif |
1759
|
|
|
|
|
|
|
#ifdef SQLITE_MACOS_MULTITASKING |
1760
|
|
|
|
|
|
|
MPExitCriticalRegion(criticalRegion); |
1761
|
|
|
|
|
|
|
#endif |
1762
|
1311
|
|
|
|
|
|
} |
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
/* |
1765
|
|
|
|
|
|
|
** Turn a relative pathname into a full pathname. Return a pointer |
1766
|
|
|
|
|
|
|
** to the full pathname stored in space obtained from sqliteMalloc(). |
1767
|
|
|
|
|
|
|
** The calling function is responsible for freeing this space once it |
1768
|
|
|
|
|
|
|
** is no longer needed. |
1769
|
|
|
|
|
|
|
*/ |
1770
|
53
|
|
|
|
|
|
char *sqliteOsFullPathname(const char *zRelative){ |
1771
|
|
|
|
|
|
|
#if OS_UNIX |
1772
|
53
|
|
|
|
|
|
char *zFull = 0; |
1773
|
53
|
100
|
|
|
|
|
if( zRelative[0]=='/' ){ |
1774
|
28
|
|
|
|
|
|
sqliteSetString(&zFull, zRelative, (char*)0); |
1775
|
|
|
|
|
|
|
}else{ |
1776
|
|
|
|
|
|
|
char zBuf[5000]; |
1777
|
25
|
|
|
|
|
|
sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative, |
1778
|
|
|
|
|
|
|
(char*)0); |
1779
|
|
|
|
|
|
|
} |
1780
|
53
|
|
|
|
|
|
return zFull; |
1781
|
|
|
|
|
|
|
#endif |
1782
|
|
|
|
|
|
|
#if OS_WIN |
1783
|
|
|
|
|
|
|
char *zNotUsed; |
1784
|
|
|
|
|
|
|
char *zFull; |
1785
|
|
|
|
|
|
|
int nByte; |
1786
|
|
|
|
|
|
|
nByte = GetFullPathName(zRelative, 0, 0, &zNotUsed) + 1; |
1787
|
|
|
|
|
|
|
zFull = sqliteMalloc( nByte ); |
1788
|
|
|
|
|
|
|
if( zFull==0 ) return 0; |
1789
|
|
|
|
|
|
|
GetFullPathName(zRelative, nByte, zFull, &zNotUsed); |
1790
|
|
|
|
|
|
|
return zFull; |
1791
|
|
|
|
|
|
|
#endif |
1792
|
|
|
|
|
|
|
#if OS_MAC |
1793
|
|
|
|
|
|
|
char *zFull = 0; |
1794
|
|
|
|
|
|
|
if( zRelative[0]==':' ){ |
1795
|
|
|
|
|
|
|
char zBuf[_MAX_PATH+1]; |
1796
|
|
|
|
|
|
|
sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]), |
1797
|
|
|
|
|
|
|
(char*)0); |
1798
|
|
|
|
|
|
|
}else{ |
1799
|
|
|
|
|
|
|
if( strchr(zRelative, ':') ){ |
1800
|
|
|
|
|
|
|
sqliteSetString(&zFull, zRelative, (char*)0); |
1801
|
|
|
|
|
|
|
}else{ |
1802
|
|
|
|
|
|
|
char zBuf[_MAX_PATH+1]; |
1803
|
|
|
|
|
|
|
sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0); |
1804
|
|
|
|
|
|
|
} |
1805
|
|
|
|
|
|
|
} |
1806
|
|
|
|
|
|
|
return zFull; |
1807
|
|
|
|
|
|
|
#endif |
1808
|
|
|
|
|
|
|
} |
1809
|
|
|
|
|
|
|
|
1810
|
|
|
|
|
|
|
/* |
1811
|
|
|
|
|
|
|
** The following variable, if set to a non-zero value, becomes the result |
1812
|
|
|
|
|
|
|
** returned from sqliteOsCurrentTime(). This is used for testing. |
1813
|
|
|
|
|
|
|
*/ |
1814
|
|
|
|
|
|
|
#ifdef SQLITE_TEST |
1815
|
|
|
|
|
|
|
int sqlite_current_time = 0; |
1816
|
|
|
|
|
|
|
#endif |
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
/* |
1819
|
|
|
|
|
|
|
** Find the current time (in Universal Coordinated Time). Write the |
1820
|
|
|
|
|
|
|
** current time and date as a Julian Day number into *prNow and |
1821
|
|
|
|
|
|
|
** return 0. Return 1 if the time and date cannot be found. |
1822
|
|
|
|
|
|
|
*/ |
1823
|
0
|
|
|
|
|
|
int sqliteOsCurrentTime(double *prNow){ |
1824
|
|
|
|
|
|
|
#if OS_UNIX |
1825
|
|
|
|
|
|
|
time_t t; |
1826
|
0
|
|
|
|
|
|
time(&t); |
1827
|
0
|
|
|
|
|
|
*prNow = t/86400.0 + 2440587.5; |
1828
|
|
|
|
|
|
|
#endif |
1829
|
|
|
|
|
|
|
#if OS_WIN |
1830
|
|
|
|
|
|
|
FILETIME ft; |
1831
|
|
|
|
|
|
|
/* FILETIME structure is a 64-bit value representing the number of |
1832
|
|
|
|
|
|
|
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). |
1833
|
|
|
|
|
|
|
*/ |
1834
|
|
|
|
|
|
|
double now; |
1835
|
|
|
|
|
|
|
GetSystemTimeAsFileTime( &ft ); |
1836
|
|
|
|
|
|
|
now = ((double)ft.dwHighDateTime) * 4294967296.0; |
1837
|
|
|
|
|
|
|
*prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5; |
1838
|
|
|
|
|
|
|
#endif |
1839
|
|
|
|
|
|
|
#ifdef SQLITE_TEST |
1840
|
|
|
|
|
|
|
if( sqlite_current_time ){ |
1841
|
|
|
|
|
|
|
*prNow = sqlite_current_time/86400.0 + 2440587.5; |
1842
|
|
|
|
|
|
|
} |
1843
|
|
|
|
|
|
|
#endif |
1844
|
0
|
|
|
|
|
|
return 0; |
1845
|
|
|
|
|
|
|
} |