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