+/* Check if the database MDB should be reloaded or not. It returns:
+
+ 1: The database has not been updated since it was loaded last
+ time.
+
+ 0: The database has never been loaded or has been updated
+ since it was loaded last time.
+
+ -1: The database is not loadable at the moment. */
+
+int
+mdatabase__check (MDatabase *mdb)
+{
+ MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
+ struct stat buf;
+
+ if (! get_database_file (db_info, &buf))
+ return -1;
+ if (db_info->time < buf.st_mtime)
+ return 0;
+ if (db_info->status == MDB_STATUS_AUTO
+ && db_info->filename != db_info->absolute_filename)
+ {
+ MDatabase *new;
+
+ mdatabase__update ();
+ new = find_database (mdb->tag);
+ if (new != mdb)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Search directories in mdatabase__dir_list for file FILENAME. If
+ the file exist, return the absolute pathname. If FILENAME is
+ already absolute, return a copy of it. */
+
+char *
+mdatabase__find_file (char *filename)
+{
+ struct stat buf;
+ MDatabaseInfo db_info;
+
+ if (filename[0] == PATH_SEPARATOR)
+ return (stat (filename, &buf) == 0 ? filename : NULL);
+ db_info.filename = filename;
+ db_info.len = strlen (filename);
+ db_info.time = 0;
+ db_info.absolute_filename = NULL;
+ if (! get_database_file (&db_info, &buf)
+ || stat (db_info.absolute_filename, &buf) < 0)
+ return NULL;
+ return db_info.absolute_filename;
+}
+
+char *
+mdatabase__file (MDatabase *mdb)
+{
+ MDatabaseInfo *db_info;
+
+ if (mdb->loader != load_database)
+ return NULL;
+ db_info = mdb->extra_info;
+ return get_database_file (db_info, NULL);
+}
+
+int
+mdatabase__lock (MDatabase *mdb)
+{
+ MDatabaseInfo *db_info;
+ struct stat buf;
+ FILE *fp;
+ int len;
+ char *file;
+
+ if (mdb->loader != load_database)
+ return -1;
+ db_info = mdb->extra_info;
+ if (db_info->lock_file)
+ return -1;
+ file = get_database_file (db_info, NULL);
+ if (! file)
+ return -1;
+ len = strlen (file);
+ db_info->uniq_file = malloc (len + 35);
+ if (! db_info->uniq_file)
+ return -1;
+ db_info->lock_file = malloc (len + 5);
+ if (! db_info->lock_file)
+ {
+ free (db_info->uniq_file);
+ return -1;
+ }
+ sprintf (db_info->uniq_file, "%s.%X.%X", db_info->absolute_filename,
+ (unsigned) time (NULL), (unsigned) getpid ());
+ sprintf (db_info->lock_file, "%s.LCK", db_info->absolute_filename);
+
+ fp = fopen (db_info->uniq_file, "w");
+ if (! fp)
+ {
+ char *str = strdup (db_info->uniq_file);
+ char *dir = dirname (str);
+
+ if (stat (dir, &buf) == 0
+ || mkdir (dir, 0777) < 0
+ || ! (fp = fopen (db_info->uniq_file, "w")))
+ {
+ free (db_info->uniq_file);
+ free (db_info->lock_file);
+ db_info->lock_file = NULL;
+ free (str);
+ return -1;
+ }
+ free (str);
+ }
+ fclose (fp);
+ if (link (db_info->uniq_file, db_info->lock_file) < 0
+ && (stat (db_info->uniq_file, &buf) < 0
+ || buf.st_nlink != 2))
+ {
+ unlink (db_info->uniq_file);
+ unlink (db_info->lock_file);
+ free (db_info->uniq_file);
+ free (db_info->lock_file);
+ db_info->lock_file = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+int
+mdatabase__save (MDatabase *mdb, MPlist *data)
+{
+ MDatabaseInfo *db_info;
+ FILE *fp;
+ char *file;
+ MText *mt;
+ int ret;
+
+ if (mdb->loader != load_database)
+ return -1;
+ db_info = mdb->extra_info;
+ if (! db_info->lock_file)
+ return -1;
+ file = get_database_file (db_info, NULL);
+ if (! file)
+ return -1;
+ mt = mtext ();
+ if (mplist__serialize (mt, data, 1) < 0)
+ {
+ M17N_OBJECT_UNREF (mt);
+ return -1;
+ }
+ fp = fopen (db_info->uniq_file, "w");
+ if (! fp)
+ {
+ M17N_OBJECT_UNREF (mt);
+ return -1;
+ }
+ mconv_encode_stream (msymbol ("utf-8"), mt, fp);
+ M17N_OBJECT_UNREF (mt);
+ fclose (fp);
+ if ((ret = rename (db_info->uniq_file, file)) < 0)
+ unlink (db_info->uniq_file);
+ free (db_info->uniq_file);
+ db_info->uniq_file = NULL;
+ return ret;
+}
+
+int
+mdatabase__unlock (MDatabase *mdb)
+{
+ MDatabaseInfo *db_info;
+
+ if (mdb->loader != load_database)
+ return -1;
+ db_info = mdb->extra_info;
+ if (! db_info->lock_file)
+ return -1;
+ unlink (db_info->lock_file);
+ free (db_info->lock_file);
+ db_info->lock_file = NULL;
+ if (db_info->uniq_file)
+ {
+ unlink (db_info->uniq_file);
+ free (db_info->uniq_file);
+ }
+ return 0;
+}
+