00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: os__fid_8c-source.html,v 1.1 2008/06/08 10:21:13 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 #include <sys/stat.h> 00017 00018 #if TIME_WITH_SYS_TIME 00019 #include <sys/time.h> 00020 #include <time.h> 00021 #else 00022 #if HAVE_SYS_TIME_H 00023 #include <sys/time.h> 00024 #else 00025 #include <time.h> 00026 #endif 00027 #endif 00028 00029 #include <string.h> 00030 #include <unistd.h> 00031 #endif 00032 00033 #include "db_int.h" 00034 00035 #define SERIAL_INIT 0 00036 static u_int32_t fid_serial = SERIAL_INIT; 00037 00038 /* 00039 * CDB___os_fileid -- 00040 * Return a unique identifier for a file. 00041 * 00042 * PUBLIC: int CDB___os_fileid __P((DB_ENV *, const char *, int, u_int8_t *)); 00043 */ 00044 int 00045 CDB___os_fileid(dbenv, fname, unique_okay, fidp) 00046 DB_ENV *dbenv; 00047 const char *fname; 00048 int unique_okay; 00049 u_int8_t *fidp; 00050 { 00051 struct stat sb; 00052 size_t i; 00053 int ret; 00054 u_int32_t tmp; 00055 u_int8_t *p; 00056 00057 /* Clear the buffer. */ 00058 memset(fidp, 0, DB_FILE_ID_LEN); 00059 00060 /* On POSIX/UNIX, use a dev/inode pair. */ 00061 if (stat(fname, &sb)) { 00062 ret = CDB___os_get_errno(); 00063 CDB___db_err(dbenv, "%s: %s", fname, strerror(ret)); 00064 return (ret); 00065 } 00066 00067 /* 00068 * Initialize/increment the serial number we use to help avoid 00069 * fileid collisions. Note that we don't bother with locking; 00070 * it's unpleasant to do from down in here, and if we race on 00071 * this no real harm will be done, since the finished fileid 00072 * has so many other components. 00073 * 00074 * We increment by 100000 on each call as a simple way of 00075 * randomizing; simply incrementing seems potentially less useful 00076 * if pids are also simply incremented, since this is process-local 00077 * and we may be one of a set of processes starting up. 100000 00078 * pushes us out of pid space on most platforms, and has few 00079 * interesting properties in base 2. 00080 */ 00081 if (fid_serial == SERIAL_INIT) 00082 fid_serial = (u_int32_t)getpid(); 00083 else 00084 fid_serial += 100000; 00085 00086 /* 00087 * !!! 00088 * Nothing is ever big enough -- on Sparc V9, st_ino, st_dev and the 00089 * time_t types are all 8 bytes. As DB_FILE_ID_LEN is only 20 bytes, 00090 * we convert to a (potentially) smaller fixed-size type and use it. 00091 * 00092 * We don't worry about byte sexing or the actual variable sizes. 00093 * 00094 * When this routine is called from the DB access methods, it's only 00095 * called once -- whatever ID is generated when a database is created 00096 * is stored in the database file's metadata, and that is what is 00097 * saved in the mpool region's information to uniquely identify the 00098 * file. 00099 * 00100 * When called from the mpool layer this routine will be called each 00101 * time a new thread of control wants to share the file, which makes 00102 * things tougher. As far as byte sexing goes, since the mpool region 00103 * lives on a single host, there's no issue of that -- the entire 00104 * region is byte sex dependent. As far as variable sizes go, we make 00105 * the simplifying assumption that 32-bit and 64-bit processes will 00106 * get the same 32-bit values if we truncate any returned 64-bit value 00107 * to a 32-bit value. When we're called from the mpool layer, though, 00108 * we need to be careful not to include anything that isn't 00109 * reproducible for a given file, such as the timestamp or serial 00110 * number. 00111 */ 00112 tmp = (u_int32_t)sb.st_ino; 00113 for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) 00114 *fidp++ = *p++; 00115 00116 tmp = (u_int32_t)sb.st_dev; 00117 for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) 00118 *fidp++ = *p++; 00119 00120 if (unique_okay) { 00121 /* 00122 * We want the number of seconds, not the high-order 0 bits, 00123 * so convert the returned time_t to a (potentially) smaller 00124 * fixed-size type. 00125 */ 00126 tmp = (u_int32_t)time(NULL); 00127 for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) 00128 *fidp++ = *p++; 00129 00130 for (p = (u_int8_t *)&fid_serial, i = sizeof(u_int32_t); 00131 i > 0; --i) 00132 *fidp++ = *p++; 00133 } 00134 00135 return (0); 00136 }