Пример #1
0
/*
 * strhash_open: open string hash table.
 *
 *	i)	buckets	 size of bucket table
 *	r)	sh	STRHASH structure
 */
STRHASH *
strhash_open(int buckets)
{
	STRHASH *sh = (STRHASH *)check_calloc(sizeof(STRHASH), 1);
	int i;

	sh->htab = (struct sh_head *)check_calloc(sizeof(struct sh_head), buckets);
	for (i = 0; i < buckets; i++)
		SLIST_INIT(&sh->htab[i]);
	sh->buckets = buckets;
	sh->pool = pool_open();
	sh->entries = 0;
	return sh;
}
Пример #2
0
/*
 * convert_open: open convert filter
 *
 *	i)	type	PATH_ABSOLUTE, PATH_RELATIVE, PATH_THROUGH
 *	i)	format	tag record format
 *	i)	root	root directory of source tree
 *	i)	cwd	current directory
 *	i)	dbpath	dbpath directory
 *	i)	op	output file
 */
CONVERT *
convert_open(int type, int format, const char *root, const char *cwd, const char *dbpath, FILE *op)
{
	CONVERT *cv = (CONVERT *)check_calloc(sizeof(CONVERT), 1);
	/*
	 * set base directory.
	 */
	cv->abspath = strbuf_open(MAXPATHLEN);
	strbuf_puts(cv->abspath, root);
	strbuf_unputc(cv->abspath, '/');
	cv->start_point = strbuf_getlen(cv->abspath);
	/*
	 * copy elements.
	 */
	if (strlen(cwd) > MAXPATHLEN)
		die("current directory name too long.");
	strlimcpy(cv->basedir, cwd, sizeof(cv->basedir));
	cv->type = type;
	cv->format = format;
	cv->op = op;
	/*
	 * open GPATH.
	 */
	if (gpath_open(dbpath, 0) < 0)
		die("GPATH not found.");
	return cv;
}
Пример #3
0
/**
 * rewrite_open: open rewrite object
 *
 *	@param[in]	pattern
 *			accepts NULL
 *	@param[in]	replace (allows '&')
 *	@param[in]	flags for regcomp(3)
 *	@return	rewrite	#REWRITE structure
 *			NULL: invalid regular expression
 */
REWRITE *
rewrite_open(const char *pattern, const char *replace, int flags)
{
	REWRITE *rewrite = (REWRITE *)check_calloc(sizeof(REWRITE), 1);
	char *p;

	if (pattern) {
		if (regcomp(&rewrite->reg, pattern, flags) != 0) {
			free(rewrite);
			return NULL;
		}
		rewrite->pattern = check_strdup(pattern);
	}
	rewrite->replace = check_strdup(replace);
	if ((p = strchr(rewrite->replace, '&')) != NULL) {
		if (p > rewrite->replace) {
			*p = '\0';
			rewrite->part[REWRITE_LEFT] = rewrite->replace;
			rewrite->len[REWRITE_LEFT] = strlen(rewrite->replace);
		}
		if (*++p != 0) {
			rewrite->part[REWRITE_RIGHT] = p;
			rewrite->len[REWRITE_RIGHT] = strlen(p);
		}
	} else {
		rewrite->part[REWRITE_CENTER]  = rewrite->replace;
		rewrite->len[REWRITE_CENTER]  = strlen(rewrite->replace);
	}
	return rewrite;
}
Пример #4
0
/**
 * pool_open: open memory pool
 *
 *	@return	pool	POOL structure
 */
POOL *
pool_open(void)
{
	POOL *pool = (POOL *)check_calloc(sizeof(POOL), 1);

	obstack_init(&pool->obstack);
	pool->first_object = obstack_alloc(&pool->obstack, 1);
	return pool;
}
Пример #5
0
/**
 * Allocate memory for new idset.
 */
IDSET *
idset_open(unsigned int size)
{
	IDSET *idset = (IDSET *)check_malloc(sizeof(IDSET));
	int i;

	if (bit == NULL) {
		bit = (unsigned long *)check_calloc(sizeof(unsigned long), LONG_BIT);
		for (i = 0; i < LONG_BIT; i++)
			bit[i] = 1UL << i;
	}
	idset->set = (unsigned long *)check_calloc(sizeof(unsigned long), (size + LONG_BIT - 1) / LONG_BIT);
	idset->size = size;
	/*
	 * Initialize all id expressions using invalid value.
	 * END_OF_ID means 'no value' or 'out of range'.
	 */
	idset->min = idset->max = idset->lastid = END_OF_ID;
	return idset;
}
Пример #6
0
struct chr_val_array *chr_val_array_create(struct byte_array *name)
{
        struct chr_val_array *result = check_malloc(sizeof(*result));
        result->refs = 1;
        result->name = byte_array_copy(name);
        result->length = 0;
        result->capacity = START_CAPABILITY;
        result->items = check_calloc(START_CAPABILITY, sizeof(struct chr_val *));

        return result;
}
Пример #7
0
/**
 * varray_open: open virtual array.
 *
 *	@param[in]	size	size of entry
 *	@param[in]	expand	expand array size <br>
 *			if 0 (zero) is specified then use #DEFAULT_EXPAND.
 *	@return	vb	#VARRAY structure
 */
VARRAY *
varray_open(int size, int expand)
{
	VARRAY *vb = (VARRAY *)check_calloc(sizeof(VARRAY), 1);

	if (size < 1)
		die("varray_open: size < 1.");
	if (expand < 0)
		die("varray_open: expand < 0.");
	vb->size = size;
	vb->alloced = vb->length = 0;
	vb->expand = (expand == 0) ? DEFAULT_EXPAND : expand;
	vb->vbuf = NULL;
	return vb;
}
Пример #8
0
int main(void)
{
	unsigned int i;

	check_events();
	check_small_alloc();
	check_malloc_zero();
	check_calloc();

	check_torture(3);
	check_torture(5);
	check_torture(7);
	for (i = 8; i < (16 * 1024); i = i * 2)
		check_torture(i);
	check_torture(9 * 1024);
	return 0;
}
Пример #9
0
/**
 * gfind_open: start iterator using GPATH.
 *
 *	@param[in]	dbpath  dbpath
 *	@param[in]	local   local prefix,
 *			if NULL specified, it assumes "./";
 *	@param[in]      target  GPATH_SOURCE: only source file,
 *			GPATH_OTHER: only other file,
 *			GPATH_BOTH: source file + other file
 *	@param[in]	flags	GPATH_NEARSORT
 *	@return		GFIND structure
 */
GFIND *
gfind_open(const char *dbpath, const char *local, int target, int flags)
{
	GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1);

	gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0);
	if (gfind->dbop == NULL)
		die("GPATH not found.");
	gfind->path = NULL;
	gfind->prefix = check_strdup(local ? local : "./");
	gfind->first = 1;
	gfind->eod = 0;
	gfind->target = target;
	gfind->type = GPATH_SOURCE;
	gfind->flags = flags;
	gfind->path_array = NULL;
	gfind->version = dbop_getversion(gfind->dbop);
	if (gfind->version > support_version)
		die("GPATH seems new format. Please install the latest GLOBAL.");
	else if (gfind->version < support_version)
		die("GPATH seems older format. Please remake tag files."); 
	/*
	 * Nearness sort.
	 * In fact, this timing of sort is not good for performance.
	 * Reconsideration is needed later.
	 */
	if (gfind->flags & GPATH_NEARSORT) {
		const char *path = NULL;
		VARRAY *varray = varray_open(sizeof(char *), 100);
		POOL *pool = pool_open();
		while ((path = gfind_read(gfind)) != NULL) {
			char **a = varray_append(varray);
			*a = pool_strdup(pool, path, 0);
		}
		if ((nearbase = get_nearbase_path()) == NULL)
			die("cannot get nearbase path.");
		qsort(varray_assign(varray, 0, 0), varray->length, sizeof(char *), compare_nearpath);
		gfind->path_array = varray;
		gfind->pool = pool;
		gfind->index = 0;
	}
	return gfind;
}
Пример #10
0
void CheckModule::check_functions(const llvm::Module *M){
  check_pthread_create(M);
  check_pthread_join(M);
  check_pthread_self(M);
  check_pthread_exit(M);
  check_pthread_mutex_init(M);
  check_pthread_mutex_lock(M);
  check_pthread_mutex_trylock(M);
  check_pthread_mutex_unlock(M);
  check_pthread_mutex_destroy(M);
  check_pthread_cond_init(M);
  check_pthread_cond_signal(M);
  check_pthread_cond_broadcast(M);
  check_pthread_cond_wait(M);
  check_pthread_cond_destroy(M);
  check_malloc(M);
  check_calloc(M);
  check_nondet_int(M);
  check_assume(M);
  std::set<std::string> supported =
    {"pthread_create",
     "pthread_join",
     "pthread_self",
     "pthread_exit",
     "pthread_mutex_init",
     "pthread_mutex_lock",
     "pthread_mutex_trylock",
     "pthread_mutex_unlock",
     "pthread_mutex_destroy",
     "pthread_cond_init",
     "pthread_cond_signal",
     "pthread_cond_broadcast",
     "pthread_cond_wait",
     "pthread_cond_destroy"};
  for(auto it = M->getFunctionList().begin(); it != M->getFunctionList().end(); ++it){
    if(it->getName().startswith("pthread_") &&
       supported.count(it->getName()) == 0){
      Debug::warn("CheckModule:"+it->getName().str())
        << "WARNING: Unsupported pthread function: " << it->getName() << "\n";
    }
  }
}
Пример #11
0
/**
 * xargs_open_generic: allocate generic part of xargs structure.
 *
 *	@param[in]	command	command line except for the arguments.
 *	@param[in]	max_args 0: no limit, \>0: max argument
 *	@return		xargs structure	
 */
static XARGS *
xargs_open_generic(const char *command, int max_args)
{
	XARGS *xp;

	xp  = check_calloc(sizeof(XARGS), 1);
	xp->command = check_strdup(command);
	xp->type = 0;
	xp->pipe = NULL;
	xp->result = strbuf_open(0);
	xp->end_of_arg = 0;
	xp->unread = 0;
	xp->max_args = max_args;
	xp->seqno = 0;
	xp->skip_assembly = 0;
	/*
	 * Procedure to display verbose message.
	 * proc(path, seqno, skip)
	 */
	xp->verbose = NULL;
	/*
	 * By default, the error status returned by pclose() is not ignored,
	 * because global(1) doesn't return error code when the target
	 * was not found.
	 * Some commands like grep(1) return error code when the target
	 * was not found. If you would like to use such command, set the
	 * flag to 1.
	 */
	xp->ignore_error = 0;
	/*
	 * By default, we doesn't put the path to GPATH.
	 * This option is prepared for createtags() and updatetags().
	 */
	xp->put_gpath = 0;
	/*
	 * By default, we don't cut off the blanks at the tail of the line.
	 */
	xp->trim_line = 0;

	return xp;
}
Пример #12
0
/*
 * gfind_open: start iterator using GPATH.
 *
 *	i)	dbpath	dbpath
 *	i)	local	local prefix
 *			if NULL specified, it assumes "./";
 *	i)	target	GPATH_SOURCE: only source file
 *			GPATH_OTHER: only other file
 *			GPATH_BOTH: source file + other file
 *	r)		GFIND structure
 */
GFIND *
gfind_open(const char *dbpath, const char *local, int target)
{
	GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1);

	gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0);
	if (gfind->dbop == NULL)
		die("GPATH not found.");
	gfind->path = NULL;
	gfind->prefix = check_strdup(local ? local : "./");
	gfind->first = 1;
	gfind->eod = 0;
	gfind->target = target;
	gfind->type = GPATH_SOURCE;
	gfind->version = dbop_getversion(gfind->dbop);
	if (gfind->version > support_version)
		die("GPATH seems new format. Please install the latest GLOBAL.");
	else if (gfind->version < support_version)
		die("GPATH seems older format. Please remake tag files."); 
	return gfind;
}
Пример #13
0
/**
 * gtags_open: open global tag.
 *
 *	@param[in]	dbpath	dbpath directory
 *	@param[in]	root	root directory (needed when compact format)
 *	@param[in]	db	#GTAGS, #GRTAGS, #GSYMS
 *	@param[in]	mode	#GTAGS_READ: read only <br>
 *			#GTAGS_CREATE: create tag <br>
 *			#GTAGS_MODIFY: modify tag
 *	@param[in]	flags	#GTAGS_COMPACT: compact format
 *	@return		#GTOP structure
 *
 * @note when error occurred, @NAME{gtags_open()} doesn't return.
 */
GTOP *
gtags_open(const char *dbpath, const char *root, int db, int mode, int flags)
{
	GTOP *gtop;
	char tagfile[MAXPATHLEN];
	int dbmode;

	gtop = (GTOP *)check_calloc(sizeof(GTOP), 1);
	gtop->db = db;
	gtop->mode = mode;
	gtop->openflags = flags;
	/*
	 * Open tag file allowing duplicate records.
	 */
	switch (gtop->mode) {
	case GTAGS_READ:
		dbmode = 0;
		break;
	case GTAGS_CREATE:
		dbmode = 1;
		break;
	case GTAGS_MODIFY:
		dbmode = 2;
		break;
	default:
		assert(0);
	}
	/*
	 * GRTAGS and GSYMS are virtual tag file. They are included in a real GRTAGS file.
	 * In fact, GSYMS doesn't exist now.
	 *
	 * GRTAGS:	tags which belongs to GRTAGS, and are defined in GTAGS.
	 * GSYMS:	tags which belongs to GRTAGS, and is not defined in GTAGS.
	 */
	strlimcpy(tagfile, makepath(dbpath, dbname(db == GSYMS ? GRTAGS : db), NULL), sizeof(tagfile));
	gtop->dbop = dbop_open(tagfile, dbmode, 0644, DBOP_DUP|DBOP_SORTED_WRITE);
	if (gtop->dbop == NULL) {
		if (dbmode == 1)
			die("cannot make %s.", dbname(db));
		die("%s not found.", dbname(db));
	}
	if (gtop->mode == GTAGS_READ && db != GTAGS) {
		const char *gtags = makepath(dbpath, dbname(GTAGS), NULL);
		int format_version;

		gtop->gtags = dbop_open(gtags, 0, 0, 0);
		if (gtop->gtags == NULL)
			die("GTAGS not found.");
		format_version = dbop_getversion(gtop->dbop);
		if (format_version > upper_bound_version)
			die("%s seems new format. Please install the latest GLOBAL.", gtags);
		else if (format_version < lower_bound_version)
			die("%s seems older format. Please remake tag files.", gtags);
	}
	if (gtop->mode == GTAGS_CREATE) {
		/*
		 * Decide format.
		 */
		gtop->format = 0;
		gtop->format_version = new_format_version;
		/*
		 * GRTAGS and GSYSM always use compact format.
		 * GTAGS uses compact format only when the -c option specified.
		 */
		if (gtop->db == GRTAGS || gtop->db == GSYMS || gtop->openflags & GTAGS_COMPACT) {
			gtop->format |= GTAGS_COMPACT;
			gtop->format |= GTAGS_COMPLINE;
		} else {
			/* standard format */
			gtop->format |= GTAGS_COMPRESS;
		}
		gtop->format |= GTAGS_COMPNAME;
		if (gtop->format & GTAGS_COMPACT)
			dbop_putoption(gtop->dbop, COMPACTKEY, NULL);
		if (gtop->format & GTAGS_COMPRESS) {
			dbop_putoption(gtop->dbop, COMPRESSKEY, DEFAULT_ABBREVIATION);
			abbrev_open(DEFAULT_ABBREVIATION);
		}
		if (gtop->format & GTAGS_COMPLINE)
			dbop_putoption(gtop->dbop, COMPLINEKEY, NULL);
		if (gtop->format & GTAGS_COMPNAME)
			dbop_putoption(gtop->dbop, COMPNAMEKEY, NULL);
		dbop_putversion(gtop->dbop, gtop->format_version); 
	} else {
		/*
		 * recognize format version of GTAGS. 'format version record'
		 * is saved as a META record in GTAGS and GRTAGS.
		 * if 'format version record' is not found, it's assumed
		 * version 1.
		 */
		const char *p;
		/*
		 * check format version.
		 */
		gtop->format_version = dbop_getversion(gtop->dbop);
		if (gtop->format_version > upper_bound_version)
			die("%s seems new format. Please install the latest GLOBAL.", tagfile);
		else if (gtop->format_version < lower_bound_version)
			die("%s seems older format. Please remake tag files.", tagfile);
		gtop->format = 0;
		if (dbop_getoption(gtop->dbop, COMPACTKEY) != NULL)
			gtop->format |= GTAGS_COMPACT;
		if ((p = dbop_getoption(gtop->dbop, COMPRESSKEY)) != NULL) {
			abbrev_open(p);
			gtop->format |= GTAGS_COMPRESS;
		}
		if (dbop_getoption(gtop->dbop, COMPLINEKEY) != NULL)
			gtop->format |= GTAGS_COMPLINE;
		if (dbop_getoption(gtop->dbop, COMPNAMEKEY) != NULL)
			gtop->format |= GTAGS_COMPNAME;
	}
	if (gpath_open(dbpath, dbmode) < 0) {
		if (dbmode == 1)
			die("cannot create GPATH.");
		else
			die("GPATH not found.");
	}
	if (gtop->mode != GTAGS_READ)
		gtop->sb = strbuf_open(0);	/* This buffer is used for working area. */
	/*
	 * Stuff for compact format.
	 */
	if (gtop->format & GTAGS_COMPACT) {
		assert(root != NULL);
		strlimcpy(gtop->root, root, sizeof(gtop->root));
		if (gtop->mode != GTAGS_READ)
			gtop->path_hash = strhash_open(HASHBUCKETS);
	}
	return gtop;
}
Пример #14
0
DBOP *
dbop3_open(const char *path, int mode, int perm, int flags) {
	int rc, rw = 0;
	char *errmsg = 0;
	DBOP *dbop;
	sqlite3 *db3;
	const char *tblname;
	int cache_size = 0;
	STRBUF *sql = strbuf_open_tempbuf();
	char buf[1024];

	/*
	 * When the path is NULL string and private, temporary file is used.
	 * The database will be removed when the session is closed.
	 */
	if (path == NULL) {
		path = "";
		tblname = "temp";
	} else {
		/*
		 * In case of creation.
		 */
		if (mode == 1) {
#ifndef _WIN32
			(void)truncate(path, 0);
#else
			FILE* f = fopen(path, "w");
			if (f)
				fclose(f);
#endif
		}
		tblname = "db";
	}
	/*
	 * setup arguments.
	 */
	switch (mode) {
	case 0:
		rw = SQLITE_OPEN_READONLY;
		break;
	case 1:
		rw = SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
		break;
	case 2:
		rw = SQLITE_OPEN_READWRITE;
		break;
	default:
		assert(0);
	}
	/*
	 * When the fourth argument is NULL, sqlite3_vfs is used.
	 */
	rc = sqlite3_open_v2(path, &db3, rw, NULL);
	if (rc != SQLITE_OK)
		die("sqlite3_open_v2 failed. (rc = %d)", rc);
	dbop = (DBOP *)check_calloc(sizeof(DBOP), 1);
	strlimcpy(dbop->dbname, path, sizeof(dbop->dbname));
	dbop->sb        = strbuf_open(0);
	dbop->db3       = db3;
	dbop->openflags	= flags;
	dbop->perm	= (mode == 1) ? perm : 0;
	dbop->mode      = mode;
	dbop->lastdat	= NULL;
	dbop->lastflag	= NULL;
	dbop->lastsize	= 0;
	dbop->sortout	= NULL;
	dbop->sortin	= NULL;
	dbop->stmt      = NULL;
	dbop->tblname   = check_strdup(tblname);
	/*
	 * Maximum file size is DBOP_PAGESIZE * 2147483646.
	 * if DBOP_PAGESIZE == 8192 then maximum file size is 17592186028032 (17T).
	 */
	snprintf(buf, sizeof(buf), "pragma page_size=%d", DBOP_PAGESIZE);
	rc = sqlite3_exec(dbop->db3, buf,  NULL, NULL, &errmsg);
	if (rc != SQLITE_OK)
		die("pragma page_size error: %s", errmsg);
	/*
	 * create table (GTAGS, GRTAGS, GSYMS, GPATH).
	 */
	if (mode == 1) {
		/* drop table */
		strbuf_clear(sql);
		strbuf_puts(sql, "drop table ");
		strbuf_puts(sql, dbop->tblname);
		rc = sqlite3_exec(dbop->db3, strbuf_value(sql), NULL, NULL, &errmsg);
        	if (rc != SQLITE_OK) {
			/* ignore */
		}
		/* create table */
		strbuf_clear(sql);
		strbuf_puts(sql, "create table ");
		strbuf_puts(sql, dbop->tblname);
		strbuf_puts(sql, " (key text, dat text, extra text");
		if (!(flags & DBOP_DUP))
			strbuf_puts(sql, ", primary key(key)");
		strbuf_putc(sql, ')');
		rc = sqlite3_exec(dbop->db3, strbuf_value(sql), NULL, NULL, &errmsg);
        	if (rc != SQLITE_OK)
			die("create table error: %s", errmsg);
	}
	/*
	rc = sqlite3_exec(dbop->db3, "pragma synchronous=off", NULL, NULL, &errmsg);
       	if (rc != SQLITE_OK)
		die("pragma synchronous=off error: %s", errmsg);
	*/
	/*
         * Decide cache size.
         * See libutil/gparam.h for the details.
         */
	cache_size = GTAGSCACHE;
	if (getenv("GTAGSCACHE") != NULL)
		cache_size = atoi(getenv("GTAGSCACHE"));
	if (cache_size < GTAGSMINCACHE)
		cache_size = GTAGSMINCACHE;
	cache_size = (cache_size + DBOP_PAGESIZE - 1) / DBOP_PAGESIZE;
	snprintf(buf, sizeof(buf), "pragma cache_size=%d", cache_size);
	rc = sqlite3_exec(dbop->db3, buf,  NULL, NULL, &errmsg);
       	if (rc != SQLITE_OK)
		die("pragma cache_size error: %s", errmsg);
	sqlite3_exec(dbop->db3, "pragma journal_mode=memory", NULL, NULL, &errmsg);
       	if (rc != SQLITE_OK)
		die("pragma journal_mode=memory error: %s", errmsg);
	sqlite3_exec(dbop->db3, "pragma synchronous=off", NULL, NULL, &errmsg);
       	if (rc != SQLITE_OK)
		die("pragma synchronous=off error: %s", errmsg);
	rc = sqlite3_exec(dbop->db3, "begin transaction", NULL, NULL, &errmsg);
       	if (rc != SQLITE_OK)
		die("begin transaction error: %s", errmsg);
	strbuf_release_tempbuf(sql);
	return dbop;
}
Пример #15
0
/**
 * dbop_open: open db database.
 *
 *	@param[in]	path	database name
 *	@param[in]	mode	0: read only, 1: create, 2: modify
 *	@param[in]	perm	file permission
 *	@param[in]	flags
 *			DBOP_DUP: allow duplicate records.
 *			DBOP_SORTED_WRITE: use sorted writing. This requires POSIX sort.
 *	@return		descripter for dbop_xxx() or NULL
 *
 * Sorted wirting is fast because all writing is done by not insertion but addition.
 */
DBOP *
dbop_open(const char *path, int mode, int perm, int flags)
{
	DB *db;
	int rw = 0;
	DBOP *dbop;
	BTREEINFO info;

#ifdef USE_SQLITE3
	if (mode != 1 && is_sqlite3(path))
		flags |= DBOP_SQLITE3;
	if (flags & DBOP_SQLITE3) {
		dbop = dbop3_open(path, mode, perm, flags);
		goto finish;
	}
#endif
	/*
	 * setup arguments.
	 */
	switch (mode) {
	case 0:
		rw = O_RDONLY;
		break;
	case 1:
		rw = O_RDWR|O_CREAT|O_TRUNC;
		break;
	case 2:
		rw = O_RDWR;
		break;
	default:
		assert(0);
	}
	memset(&info, 0, sizeof(info));
	if (flags & DBOP_DUP)
		info.flags |= R_DUP;
	info.psize = DBOP_PAGESIZE;
	/*
	 * Decide cache size. The default value is 5MB.
	 * See libutil/gparam.h for the details.
	 */
	info.cachesize = GTAGSCACHE;
	if (getenv("GTAGSCACHE") != NULL)
		info.cachesize = atoi(getenv("GTAGSCACHE"));
	if (info.cachesize < GTAGSMINCACHE)
		info.cachesize = GTAGSMINCACHE;

	/*
	 * if unlink do job normally, those who already open tag file can use
	 * it until closing.
	 */
	if (path != NULL && mode == 1 && test("f", path))
		(void)unlink(path);
	db = dbopen(path, rw, 0600, DB_BTREE, &info);
	if (!db)
		return NULL;
	/*
	 * if file size == 0 then it should be corrupted.
	 */
	if (mode != 1) {
		int fd = (*db->fd)(db);
		struct stat stat;

 		if (fstat(fd, &stat) < 0)
			die("fstat failed.");
		if (stat.st_size == 0) {
			errno = EFTYPE;
			return NULL;
		}
	}
	dbop = (DBOP *)check_calloc(sizeof(DBOP), 1);
	if (path == NULL)
		dbop->dbname[0] = '\0';
	else
		strlimcpy(dbop->dbname, path, sizeof(dbop->dbname));
	dbop->db	= db;
	dbop->openflags	= flags;
	dbop->perm	= (mode == 1) ? perm : 0;
	dbop->lastdat	= NULL;
	dbop->lastsize	= 0;
	dbop->sortout	= NULL;
	dbop->sortin	= NULL;
	/*
	 * Setup sorted writing.
	 */
	if (mode != 0 && dbop->openflags & DBOP_SORTED_WRITE)
		start_sort_process(dbop);
#ifdef USE_SQLITE3
finish:
#endif
	return dbop;
}