os_fid.c 4.35 KB
Newer Older
unknown's avatar
unknown committed
1 2 3
/*-
 * See the file LICENSE for redistribution information.
 *
unknown's avatar
unknown committed
4
 * Copyright (c) 1996-2002
unknown's avatar
unknown committed
5 6 7 8 9 10
 *	Sleepycat Software.  All rights reserved.
 */

#include "db_config.h"

#ifndef lint
unknown's avatar
unknown committed
11
static const char revid[] = "$Id: os_fid.c,v 11.15 2002/08/26 14:37:39 margo Exp $";
unknown's avatar
unknown committed
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
#endif /* not lint */

#include "db_int.h"

#define	SERIAL_INIT	0
static u_int32_t fid_serial = SERIAL_INIT;

/*
 * __os_fileid --
 *	Return a unique identifier for a file.
 */
int
__os_fileid(dbenv, fname, unique_okay, fidp)
	DB_ENV *dbenv;
	const char *fname;
	int unique_okay;
	u_int8_t *fidp;
{
	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 fh;
	BY_HANDLE_FILE_INFORMATION fi;
	BOOL retval = FALSE;

unknown's avatar
unknown committed
46 47
	DB_ASSERT(fname != NULL);

unknown's avatar
unknown committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	/* Clear the buffer. */
	memset(fidp, 0, DB_FILE_ID_LEN);

	/*
	 * Initialize/increment the serial number we use to help avoid
	 * fileid collisions.  Note that 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 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 platforms, and has few
	 * interesting properties in base 2.
	 */
	if (fid_serial == SERIAL_INIT)
unknown's avatar
unknown committed
66
		__os_id(&fid_serial);
unknown's avatar
unknown committed
67 68 69 70 71 72 73 74 75 76 77
	else
		fid_serial += 100000;

	/*
	 * 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(dbenv, fname, DB_OSO_RDONLY, _S_IREAD, &fh)) != 0)
		return (ret);

	/* File open, get its info */
unknown's avatar
unknown committed
78
	if ((retval = GetFileInformationByHandle(fh.handle, &fi)) == FALSE)
unknown's avatar
unknown committed
79
		ret = __os_win32_errno();
unknown's avatar
unknown committed
80
	__os_closehandle(dbenv, &fh);
unknown's avatar
unknown committed
81

unknown's avatar
unknown committed
82
	if (retval == FALSE)
unknown's avatar
unknown committed
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
		return (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++;
unknown's avatar
unknown committed
113

unknown's avatar
unknown committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
	if (unique_okay) {
		/*
		 * Use the system time to try to get a unique value
		 * within this process.  A millisecond counter
		 * overflows 32 bits in about 49 days.  So we use 8
		 * bytes, and don't bother with the volume ID, which
		 * is not very useful for our purposes.
		 */
		SYSTEMTIME st;

		GetSystemTime(&st);
		tmp = (st.wYear - 1900) * 12 + (st.wMonth - 1);
		for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
			*fidp++ = *p++;
		tmp = ((((st.wDay - 1) * 24 + st.wHour) * 60 +
			st.wMinute) * 60 + st.wSecond) * 1000 +
			st.wMilliseconds;
		for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
			*fidp++ = *p++;
		for (p = (u_int8_t *)&fid_serial, i = sizeof(u_int32_t);
		    i > 0; --i)
			*fidp++ = *p++;
	} 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);
}