1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2009 Oracle. All rights reserved.
*
* $Id$
*/
#include "db_config.h"
#include "db_int.h"
/*
* __os_fileid --
* Return a unique identifier for a file.
*/
int
__os_fileid(env, fname, unique_okay, fidp)
ENV *env;
const char *fname;
int unique_okay;
u_int8_t *fidp;
{
pid_t pid;
size_t i;
u_int32_t tmp;
u_int8_t *p;
int ret;
/*
* The documentation for GetFileInformationByHandle() states that the
* inode-type numbers are not constant between processes. Actually,
* they are, they're the NTFS MFT indexes. So, this works on NTFS,
* but perhaps not on other platforms, and perhaps not over a network.
* Can't think of a better solution right now.
*/
DB_FH *fhp;
BY_HANDLE_FILE_INFORMATION fi;
BOOL retval = FALSE;
DB_ASSERT(env, fname != NULL);
/* Clear the buffer. */
memset(fidp, 0, DB_FILE_ID_LEN);
/*
* First we open the file, because we're not given a handle to it.
* If we can't open it, we're in trouble.
*/
if ((ret = __os_open(env, fname, 0,
DB_OSO_RDONLY, DB_MODE_400, &fhp)) != 0)
return (ret);
/* File open, get its info */
if ((retval = GetFileInformationByHandle(fhp->handle, &fi)) == FALSE)
ret = __os_get_syserr();
(void)__os_closehandle(env, fhp);
if (retval == FALSE)
return (__os_posix_err(ret));
/*
* We want the three 32-bit words which tell us the volume ID and
* the file ID. We make a crude attempt to copy the bytes over to
* the callers buffer.
*
* We don't worry about byte sexing or the actual variable sizes.
*
* When this routine is called from the DB access methods, it's only
* called once -- whatever ID is generated when a database is created
* is stored in the database file's metadata, and that is what is
* saved in the mpool region's information to uniquely identify the
* file.
*
* When called from the mpool layer this routine will be called each
* time a new thread of control wants to share the file, which makes
* things tougher. As far as byte sexing goes, since the mpool region
* lives on a single host, there's no issue of that -- the entire
* region is byte sex dependent. As far as variable sizes go, we make
* the simplifying assumption that 32-bit and 64-bit processes will
* get the same 32-bit values if we truncate any returned 64-bit value
* to a 32-bit value.
*/
tmp = (u_int32_t)fi.nFileIndexLow;
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
*fidp++ = *p++;
tmp = (u_int32_t)fi.nFileIndexHigh;
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
*fidp++ = *p++;
if (unique_okay) {
/* Add in 32-bits of (hopefully) unique number. */
__os_unique_id(env, &tmp);
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
*fidp++ = *p++;
/*
* Initialize/increment the serial number we use to help
* avoid fileid collisions. Note we don't bother with
* locking; it's unpleasant to do from down in here, and
* if we race on this no real harm will be done, since the
* finished fileid has so many other components.
*
* We use the bottom 32-bits of the process ID, hoping they
* are more random than the top 32-bits (should we be on a
* machine with 64-bit process IDs).
*
* We increment by 100000 on each call as a simple way of
* randomizing; simply incrementing seems potentially less
* useful if pids are also simply incremented, since this
* is process-local and we may be one of a set of processes
* starting up. 100000 pushes us out of pid space on most
* 32-bit platforms, and has few interesting properties in
* base 2.
*/
if (DB_GLOBAL(fid_serial) == 0) {
__os_id(env->dbenv, &pid, NULL);
DB_GLOBAL(fid_serial) = (u_int32_t)pid;
} else
DB_GLOBAL(fid_serial) += 100000;
} else {
tmp = (u_int32_t)fi.dwVolumeSerialNumber;
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
*fidp++ = *p++;
}
return (0);
}
|