blob: 9455b97327785665347424bc93ad2d433203e14a [file] [log] [blame]
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Miika Pekkarinen
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
Miika Pekkarinen7136fd92006-07-25 10:44:19 +000022/*
23 * TagCache API
24 *
25 * ----------x---------x------------------x-----
26 * | | | External
27 * +---------------x-------+ | TagCache | Libraries
28 * | Modification routines | | Core |
29 * +-x---------x-----------+ | |
30 * | (R/W) | | | |
31 * | +------x-------------x-+ +-------------x-----+ |
32 * | | x==x Filters & clauses | |
33 * | | Search routines | +-------------------+ |
34 * | | x============================x DirCache
35 * | +-x--------------------+ | (optional)
36 * | | (R) |
37 * | | +-------------------------------+ +---------+ |
38 * | | | DB Commit (sort,unique,index) | | | |
39 * | | +-x--------------------------x--+ | Control | |
40 * | | | (R/W) | (R) | Thread | |
41 * | | | +----------------------+ | | | |
42 * | | | | TagCache DB Builder | | +---------+ |
43 * | | | +-x-------------x------+ | |
44 * | | | | (R) | (W) | |
45 * | | | | +--x--------x---------+ |
46 * | | | | | Temporary Commit DB | |
47 * | | | | +---------------------+ |
Miika Pekkarinend8ac6072006-08-02 17:39:34 +000048 * +-x----x-------x--+ |
Miika Pekkarinen7136fd92006-07-25 10:44:19 +000049 * | TagCache RAM DB x==\(W) +-----------------+ |
Miika Pekkarinend8ac6072006-08-02 17:39:34 +000050 * +-----------------+ \===x | |
Miika Pekkarinen7136fd92006-07-25 10:44:19 +000051 * | | | | (R) | Ram DB Loader x============x DirCache
52 * +-x----x---x---x---+ /==x | | (optional)
53 * | Tagcache Disk DB x==/ +-----------------+ |
54 * +------------------+ |
55 *
56 */
57
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000058#include <stdio.h>
Dave Chapman1feb8bd2007-05-07 13:32:56 +000059#include <stdlib.h>
60#include <ctype.h>
Miika Pekkarinena85044b2006-09-16 16:18:11 +000061#include "config.h"
Miika Pekkarinen9eec03f2008-02-17 18:35:27 +000062#include "ata_idle_notify.h"
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000063#include "thread.h"
64#include "kernel.h"
65#include "system.h"
66#include "logf.h"
67#include "string.h"
68#include "usb.h"
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000069#include "metadata.h"
70#include "id3.h"
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000071#include "tagcache.h"
Miika Pekkarinena93e5912006-03-26 12:49:19 +000072#include "buffer.h"
Miika Pekkarinenfa893c62006-04-18 18:56:56 +000073#include "crc32.h"
Miika Pekkarinena1ac7432006-10-21 20:37:33 +000074#include "misc.h"
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000075#include "settings.h"
Kevin Ferrare011a3252007-07-20 17:06:55 +000076#include "dir.h"
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +000077#include "structec.h"
Bertrik Sikkene15f8a22008-05-03 08:35:14 +000078#include "tagcache.h"
79
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000080#ifndef __PCTOOL__
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000081#include "splash.h"
82#include "lang.h"
83#include "eeprom_settings.h"
84#endif
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000085
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000086#ifdef __PCTOOL__
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000087#define yield() do { } while(0)
88#define sim_sleep(timeout) do { } while(0)
Steve Bavin6d7f68c2007-03-10 14:34:56 +000089#define do_timed_yield() do { } while(0)
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000090#endif
91
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000092#ifndef __PCTOOL__
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000093/* Tag Cache thread. */
Michael Sevakis84f5c5c2007-10-16 22:00:51 +000094static struct event_queue tagcache_queue;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000095static long tagcache_stack[(DEFAULT_STACK_SIZE + 0x4000)/sizeof(long)];
96static const char tagcache_thread_name[] = "tagcache";
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +000097#endif
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +000098
Robert Kukla28530bc2007-03-04 17:30:12 +000099#define UNTAGGED "<Untagged>"
100
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000101/* Previous path when scanning directory tree recursively. */
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000102static char curpath[TAG_MAXLEN+32];
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000103static long curpath_size = sizeof(curpath);
104
105/* Used when removing duplicates. */
106static char *tempbuf; /* Allocated when needed. */
107static long tempbufidx; /* Current location in buffer. */
108static long tempbuf_size; /* Buffer size (TEMPBUF_SIZE). */
109static long tempbuf_left; /* Buffer space left. */
110static long tempbuf_pos;
111
Miika Pekkarinenea07cd52006-03-27 07:44:32 +0000112/* Tags we want to get sorted (loaded to the tempbuf). */
Miika Pekkarinen4e976642007-02-10 12:09:28 +0000113static const int sorted_tags[] = { tag_artist, tag_album, tag_genre,
Dan Evertoneecfe9f2007-08-08 10:19:56 +0000114 tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_title };
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000115
116/* Uniqued tags (we can use these tags with filters and conditional clauses). */
Miika Pekkarinen4e976642007-02-10 12:09:28 +0000117static const int unique_tags[] = { tag_artist, tag_album, tag_genre,
Dan Evertoneecfe9f2007-08-08 10:19:56 +0000118 tag_composer, tag_comment, tag_albumartist, tag_grouping };
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000119
120/* Numeric tags (we can use these tags with conditional clauses). */
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000121static const int numeric_tags[] = { tag_year, tag_discnumber,
122 tag_tracknumber, tag_length, tag_bitrate, tag_playcount, tag_rating,
123 tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
Miika Pekkarinen9d9937a2007-04-12 20:14:05 +0000124 tag_virt_length_min, tag_virt_length_sec,
Miika Pekkarinen5e47daa2007-04-12 20:21:56 +0000125 tag_virt_playtime_min, tag_virt_playtime_sec,
Miika Pekkarinenf5184f32007-02-25 20:41:51 +0000126 tag_virt_entryage, tag_virt_autoscore };
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000127
Miika Pekkarinen4e976642007-02-10 12:09:28 +0000128/* String presentation of the tags defined in tagcache.h. Must be in correct order! */
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000129static const char *tags_str[] = { "artist", "album", "genre", "title",
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000130 "filename", "composer", "comment", "albumartist", "grouping", "year",
131 "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating",
132 "playtime", "lastplayed", "commitid", "mtime" };
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000133
Miika Pekkarinen41427102006-04-23 18:47:26 +0000134/* Status information of the tagcache. */
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000135static struct tagcache_stat tc_stat;
Miika Pekkarinen1b18dd02006-04-12 10:31:24 +0000136
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000137/* Queue commands. */
Miika Pekkarinenfa893c62006-04-18 18:56:56 +0000138enum tagcache_queue {
139 Q_STOP_SCAN = 0,
140 Q_START_SCAN,
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000141 Q_IMPORT_CHANGELOG,
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +0000142 Q_UPDATE,
143 Q_REBUILD,
Miika Pekkarinen9d756e22007-07-21 17:35:19 +0000144
145 /* Internal tagcache command queue. */
146 CMD_UPDATE_MASTER_HEADER,
147 CMD_UPDATE_NUMERIC,
Miika Pekkarinenfa893c62006-04-18 18:56:56 +0000148};
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000149
Miika Pekkarinen9d756e22007-07-21 17:35:19 +0000150struct tagcache_command_entry {
Jonathan Gordon7c0a8e12008-04-24 07:54:32 +0000151 int32_t command;
152 int32_t idx_id;
153 int32_t tag;
154 int32_t data;
Miika Pekkarinen9d756e22007-07-21 17:35:19 +0000155};
156
157static struct tagcache_command_entry command_queue[TAGCACHE_COMMAND_QUEUE_LENGTH];
158static volatile int command_queue_widx = 0;
159static volatile int command_queue_ridx = 0;
Michael Sevakis84f5c5c2007-10-16 22:00:51 +0000160static struct mutex command_queue_mutex;
Miika Pekkarinen3b313462006-04-16 17:32:54 +0000161
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000162/* Tag database structures. */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000163
164/* Variable-length tag entry in tag files. */
165struct tagfile_entry {
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000166 short tag_length; /* Length of the data in bytes including '\0' */
167 short idx_id; /* Corresponding entry location in index file of not unique tags */
168 char tag_data[0]; /* Begin of the tag data */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000169};
170
171/* Fixed-size tag entry in master db index. */
172struct index_entry {
Jonathan Gordon7c0a8e12008-04-24 07:54:32 +0000173 int32_t tag_seek[TAG_COUNT]; /* Location of tag data or numeric tag data */
174 int32_t flag; /* Status flags */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000175};
176
177/* Header is the same in every file. */
178struct tagcache_header {
Jonathan Gordon7c0a8e12008-04-24 07:54:32 +0000179 int32_t magic; /* Header version number */
180 int32_t datasize; /* Data size in bytes */
181 int32_t entry_count; /* Number of entries in this file */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000182};
183
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000184struct master_header {
185 struct tagcache_header tch;
Jonathan Gordon7c0a8e12008-04-24 07:54:32 +0000186 int32_t serial; /* Increasing counting number */
187 int32_t commitid; /* Number of commits so far */
188 int32_t dirty;
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000189};
190
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000191/* For the endianess correction */
192static const char *tagfile_entry_ec = "ss";
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000193static const char *index_entry_ec = "lllllllllllllllllllll"; /* (1 + TAG_COUNT) * l */
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000194static const char *tagcache_header_ec = "lll";
Miika Pekkarinenf5184f32007-02-25 20:41:51 +0000195static const char *master_header_ec = "llllll";
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000196
Miika Pekkarinenf5184f32007-02-25 20:41:51 +0000197static struct master_header current_tcmh;
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000198
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000199#ifdef HAVE_TC_RAMCACHE
200/* Header is created when loading database to ram. */
201struct ramcache_header {
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000202 struct master_header h; /* Header from the master index */
203 struct index_entry *indices; /* Master index file content */
204 char *tags[TAG_COUNT]; /* Tag file content (not including filename tag) */
205 int entry_count[TAG_COUNT]; /* Number of entries in the indices. */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000206};
207
Peter D'Hoyec4a59a22006-08-15 22:54:06 +0000208# ifdef HAVE_EEPROM_SETTINGS
Miika Pekkarinen954b7322006-08-05 20:19:10 +0000209struct statefile_header {
210 struct ramcache_header *hdr;
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000211 struct tagcache_stat tc_stat;
Miika Pekkarinen954b7322006-08-05 20:19:10 +0000212};
213# endif
214
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000215/* Pointer to allocated ramcache_header */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000216static struct ramcache_header *hdr;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000217#endif
218
219/**
220 * Full tag entries stored in a temporary file waiting
221 * for commit to the cache. */
222struct temp_file_entry {
223 long tag_offset[TAG_COUNT];
224 short tag_length[TAG_COUNT];
Miika Pekkarinen812cbad2006-10-04 09:05:01 +0000225 long flag;
226
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000227 long data_length;
228};
229
Miika Pekkarinen41427102006-04-23 18:47:26 +0000230struct tempbuf_id_list {
231 long id;
232 struct tempbuf_id_list *next;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000233};
234
235struct tempbuf_searchidx {
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000236 long idx_id;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000237 char *str;
238 int seek;
Miika Pekkarinen41427102006-04-23 18:47:26 +0000239 struct tempbuf_id_list idlist;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000240};
241
Miika Pekkarinen36e30812006-09-26 11:23:18 +0000242/* Lookup buffer for fixing messed up index while after sorting. */
Miika Pekkarinena47bd732006-07-22 07:09:57 +0000243static long commit_entry_count;
Miika Pekkarinen36e30812006-09-26 11:23:18 +0000244static long lookup_buffer_depth;
Jens Arnold2597a132006-12-25 14:01:47 +0000245static struct tempbuf_searchidx **lookup;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000246
247/* Used when building the temporary file. */
248static int cachefd = -1, filenametag_fd;
249static int total_entry_count = 0;
250static int data_size = 0;
251static int processed_dir_count;
252
Miika Pekkarinend8ac6072006-08-02 17:39:34 +0000253/* Thread safe locking */
254static volatile int write_lock;
255static volatile int read_lock;
256
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000257static bool delete_entry(long idx_id);
258
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000259const char* tagcache_tag_to_str(int tag)
260{
261 return tags_str[tag];
262}
263
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000264bool tagcache_is_numeric_tag(int type)
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000265{
266 int i;
267
268 for (i = 0; i < (int)(sizeof(numeric_tags)/sizeof(numeric_tags[0])); i++)
269 {
270 if (type == numeric_tags[i])
271 return true;
272 }
273
274 return false;
275}
276
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000277bool tagcache_is_unique_tag(int type)
278{
279 int i;
280
281 for (i = 0; i < (int)(sizeof(unique_tags)/sizeof(unique_tags[0])); i++)
282 {
283 if (type == unique_tags[i])
284 return true;
285 }
286
287 return false;
288}
289
290bool tagcache_is_sorted_tag(int type)
291{
292 int i;
293
294 for (i = 0; i < (int)(sizeof(sorted_tags)/sizeof(sorted_tags[0])); i++)
295 {
296 if (type == sorted_tags[i])
297 return true;
298 }
299
300 return false;
301}
302
Miika Pekkarinen784112a2008-01-13 19:34:49 +0000303#ifdef HAVE_DIRCACHE
Miika Pekkarinen39c597b2008-01-13 19:13:37 +0000304/**
305 * Returns true if specified flag is still present, i.e., dircache
306 * has not been reloaded.
307 */
308static bool is_dircache_intact(void)
309{
310 return dircache_get_appflag(DIRCACHE_APPFLAG_TAGCACHE);
311}
Miika Pekkarinen784112a2008-01-13 19:34:49 +0000312#endif
Miika Pekkarinen39c597b2008-01-13 19:13:37 +0000313
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000314static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write)
315{
316 int fd;
317 char buf[MAX_PATH];
Miika Pekkarinen91614252006-07-23 14:28:12 +0000318 int rc;
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000319
320 if (tagcache_is_numeric_tag(tag) || tag < 0 || tag >= TAG_COUNT)
321 return -1;
322
323 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag);
324
325 fd = open(buf, write ? O_RDWR : O_RDONLY);
326 if (fd < 0)
327 {
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000328 logf("tag file open failed: tag=%d write=%d file=%s", tag, write, buf);
329 tc_stat.ready = false;
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000330 return fd;
331 }
332
333 /* Check the header. */
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000334 rc = ecread(fd, hdr, 1, tagcache_header_ec, tc_stat.econ);
Miika Pekkarinen91614252006-07-23 14:28:12 +0000335 if (hdr->magic != TAGCACHE_MAGIC || rc != sizeof(struct tagcache_header))
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000336 {
337 logf("header error");
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000338 tc_stat.ready = false;
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000339 close(fd);
340 return -2;
341 }
Miika Pekkarinen36e30812006-09-26 11:23:18 +0000342
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000343 return fd;
344}
345
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000346static int open_master_fd(struct master_header *hdr, bool write)
347{
348 int fd;
349 int rc;
350
351 fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY);
352 if (fd < 0)
353 {
354 logf("master file open failed for R/W");
355 tc_stat.ready = false;
356 return fd;
357 }
358
359 tc_stat.econ = false;
360
361 /* Check the header. */
362 rc = read(fd, hdr, sizeof(struct master_header));
363 if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
364 {
365 /* Success. */
366 return fd;
367 }
368
369 /* Trying to read again, this time with endianess correction enabled. */
370 lseek(fd, 0, SEEK_SET);
371
372 rc = ecread(fd, hdr, 1, master_header_ec, true);
373 if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
374 {
375 logf("header error");
376 tc_stat.ready = false;
377 close(fd);
378 return -2;
379 }
380
381 tc_stat.econ = true;
382
383 return fd;
384}
385
Steve Bavin6d7f68c2007-03-10 14:34:56 +0000386#ifndef __PCTOOL__
387static bool do_timed_yield(void)
388{
389 /* Sorting can lock up for quite a while, so yield occasionally */
390 static long wakeup_tick = 0;
391 if (current_tick >= wakeup_tick)
392 {
393 wakeup_tick = current_tick + (HZ/4);
394 yield();
395 return true;
396 }
397 return false;
398}
399#endif
400
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +0000401#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000402static long find_entry_ram(const char *filename,
Kevin Ferrare011a3252007-07-20 17:06:55 +0000403 const struct dirent *dc)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000404{
405 static long last_pos = 0;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000406 int i;
407
408 /* Check if we tagcache is loaded into ram. */
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000409 if (!tc_stat.ramcache)
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000410 return -1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000411
412 if (dc == NULL)
413 dc = dircache_get_entry_ptr(filename);
414
415 if (dc == NULL)
416 {
417 logf("tagcache: file not found.");
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000418 return -1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000419 }
420
421 try_again:
422
423 if (last_pos > 0)
424 i = last_pos;
425 else
426 i = 0;
427
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000428 for (; i < hdr->h.tch.entry_count; i++)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000429 {
430 if (hdr->indices[i].tag_seek[tag_filename] == (long)dc)
431 {
432 last_pos = MAX(0, i - 3);
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000433 return i;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000434 }
435
Steve Bavin6d7f68c2007-03-10 14:34:56 +0000436 do_timed_yield();
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000437 }
438
439 if (last_pos > 0)
440 {
441 last_pos = 0;
442 goto try_again;
443 }
444
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000445 return -1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000446}
447#endif
448
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000449static long find_entry_disk(const char *filename)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000450{
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000451 struct tagcache_header tch;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000452 static long last_pos = -1;
453 long pos_history[POS_HISTORY_COUNT];
454 long pos_history_idx = 0;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000455 bool found = false;
456 struct tagfile_entry tfe;
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000457 int fd;
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000458 char buf[TAG_MAXLEN+32];
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000459 int i;
460 int pos = -1;
461
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000462 if (!tc_stat.ready)
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000463 return -2;
464
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000465 fd = filenametag_fd;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000466 if (fd < 0)
467 {
468 last_pos = -1;
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000469 if ( (fd = open_tag_fd(&tch, tag_filename, false)) < 0)
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000470 return -1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000471 }
472
473 check_again:
474
475 if (last_pos > 0)
476 lseek(fd, last_pos, SEEK_SET);
Miika Pekkarinen9c0b54a2006-07-24 12:10:50 +0000477 else
478 lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000479
480 while (true)
481 {
482 pos = lseek(fd, 0, SEEK_CUR);
483 for (i = pos_history_idx-1; i >= 0; i--)
484 pos_history[i+1] = pos_history[i];
485 pos_history[0] = pos;
486
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000487 if (ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ)
488 != sizeof(struct tagfile_entry))
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000489 {
490 break ;
491 }
492
493 if (tfe.tag_length >= (long)sizeof(buf))
494 {
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +0000495 logf("too long tag #1");
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000496 close(fd);
497 last_pos = -1;
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000498 return -2;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000499 }
500
501 if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
502 {
503 logf("read error #2");
504 close(fd);
505 last_pos = -1;
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000506 return -3;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000507 }
508
509 if (!strcasecmp(filename, buf))
510 {
511 last_pos = pos_history[pos_history_idx];
512 found = true;
513 break ;
514 }
515
516 if (pos_history_idx < POS_HISTORY_COUNT - 1)
517 pos_history_idx++;
518 }
519
520 /* Not found? */
521 if (!found)
522 {
523 if (last_pos > 0)
524 {
525 last_pos = -1;
526 logf("seek again");
527 goto check_again;
528 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000529
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000530 if (fd != filenametag_fd)
531 close(fd);
532 return -4;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000533 }
534
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000535 if (fd != filenametag_fd)
536 close(fd);
537
538 return tfe.idx_id;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +0000539}
540
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000541static int find_index(const char *filename)
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000542{
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000543 long idx_id = -1;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000544
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000545#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
Miika Pekkarinen39c597b2008-01-13 19:13:37 +0000546 if (tc_stat.ramcache && is_dircache_intact())
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000547 idx_id = find_entry_ram(filename, NULL);
548#endif
549
550 if (idx_id < 0)
551 idx_id = find_entry_disk(filename);
552
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000553 return idx_id;
554}
555
556bool tagcache_find_index(struct tagcache_search *tcs, const char *filename)
557{
558 int idx_id;
559
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000560 if (!tc_stat.ready)
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000561 return false;
562
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000563 idx_id = find_index(filename);
564 if (idx_id < 0)
565 return false;
566
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000567 if (!tagcache_search(tcs, tag_filename))
568 return false;
569
570 tcs->entry_count = 0;
571 tcs->idx_id = idx_id;
572
573 return true;
574}
575
Miika Pekkarinendafa0d42006-07-24 15:35:46 +0000576static bool get_index(int masterfd, int idxid,
577 struct index_entry *idx, bool use_ram)
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000578{
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000579 bool localfd = false;
580
Miika Pekkarinen42946152006-08-30 18:18:37 +0000581 if (idxid < 0)
582 {
583 logf("Incorrect idxid: %d", idxid);
584 return false;
585 }
586
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000587#ifdef HAVE_TC_RAMCACHE
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000588 if (tc_stat.ramcache && use_ram)
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000589 {
Miika Pekkarinenf9bfd732006-04-19 18:56:59 +0000590 if (hdr->indices[idxid].flag & FLAG_DELETED)
591 return false;
592
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000593 memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry));
594 return true;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000595 }
Jens Arnolda5f42cb2006-08-02 06:57:13 +0000596#else
597 (void)use_ram;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000598#endif
599
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000600 if (masterfd < 0)
601 {
602 struct master_header tcmh;
603
604 localfd = true;
605 masterfd = open_master_fd(&tcmh, false);
606 if (masterfd < 0)
607 return false;
608 }
609
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000610 lseek(masterfd, idxid * sizeof(struct index_entry)
Miika Pekkarinencb8c7952006-07-20 12:19:31 +0000611 + sizeof(struct master_header), SEEK_SET);
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000612 if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ)
613 != sizeof(struct index_entry))
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000614 {
615 logf("read error #3");
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000616 if (localfd)
617 close(masterfd);
618
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000619 return false;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000620 }
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000621
Miika Pekkarinenf6039462007-12-16 21:10:26 +0000622 if (localfd)
623 close(masterfd);
624
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000625 if (idx->flag & FLAG_DELETED)
626 return false;
627
628 return true;
629}
630
631static bool write_index(int masterfd, int idxid, struct index_entry *idx)
632{
Miika Pekkarinendafa0d42006-07-24 15:35:46 +0000633 /* We need to exclude all memory only flags & tags when writing to disk. */
634 if (idx->flag & FLAG_DIRCACHE)
635 {
636 logf("memory only flags!");
637 return false;
638 }
639
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000640#ifdef HAVE_TC_RAMCACHE
Miika Pekkarinen4cee8d92007-05-27 11:40:55 +0000641 /* Only update numeric data. Writing the whole index to RAM by memcpy
642 * destroys dircache pointers!
643 */
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000644 if (tc_stat.ramcache)
Miika Pekkarinendafa0d42006-07-24 15:35:46 +0000645 {
Miika Pekkarinen4cee8d92007-05-27 11:40:55 +0000646 int tag;
647 struct index_entry *idx_ram = &hdr->indices[idxid];
648
649 for (tag = 0; tag < TAG_COUNT; tag++)
650 {
651 if (tagcache_is_numeric_tag(tag))
652 {
653 idx_ram->tag_seek[tag] = idx->tag_seek[tag];
654 }
655 }
656
657 /* Don't touch the dircache flag. */
658 idx_ram->flag = idx->flag | (idx_ram->flag & FLAG_DIRCACHE);
Miika Pekkarinendafa0d42006-07-24 15:35:46 +0000659 }
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000660#endif
661
662 lseek(masterfd, idxid * sizeof(struct index_entry)
663 + sizeof(struct master_header), SEEK_SET);
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000664 if (ecwrite(masterfd, idx, 1, index_entry_ec, tc_stat.econ)
665 != sizeof(struct index_entry))
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000666 {
667 logf("write error #3");
Miika Pekkarinend8ac6072006-08-02 17:39:34 +0000668 logf("idxid: %d", idxid);
Miika Pekkarinen86f07c72006-07-23 15:35:53 +0000669 return false;
670 }
671
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000672 return true;
673}
674
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +0000675static bool open_files(struct tagcache_search *tcs, int tag)
676{
677 if (tcs->idxfd[tag] < 0)
678 {
679 char fn[MAX_PATH];
680
681 snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tag);
682 tcs->idxfd[tag] = open(fn, O_RDONLY);
683 }
684
685 if (tcs->idxfd[tag] < 0)
686 {
687 logf("File not open!");
688 return false;
689 }
690
691 return true;
692}
693
694static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx,
695 int tag, char *buf, long size)
696{
697 struct tagfile_entry tfe;
698 long seek;
699
700 *buf = '\0';
701
702 if (tagcache_is_numeric_tag(tag))
703 return false;
704
705 seek = idx->tag_seek[tag];
706 if (seek < 0)
707 {
708 logf("Retrieve failed");
709 return false;
710 }
711
712#ifdef HAVE_TC_RAMCACHE
713 if (tcs->ramsearch)
714 {
715 struct tagfile_entry *ep;
716
717# ifdef HAVE_DIRCACHE
Miika Pekkarinen39c597b2008-01-13 19:13:37 +0000718 if (tag == tag_filename && (idx->flag & FLAG_DIRCACHE)
719 && is_dircache_intact())
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +0000720 {
Kevin Ferrare011a3252007-07-20 17:06:55 +0000721 dircache_copy_path((struct dirent *)seek,
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +0000722 buf, size);
723 return true;
724 }
725 else
726# endif
727 if (tag != tag_filename)
728 {
729 ep = (struct tagfile_entry *)&hdr->tags[tag][seek];
730 strncpy(buf, ep->tag_data, size-1);
731
732 return true;
733 }
734 }
735#endif
736
737 if (!open_files(tcs, tag))
738 return false;
739
740 lseek(tcs->idxfd[tag], seek, SEEK_SET);
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000741 if (ecread(tcs->idxfd[tag], &tfe, 1, tagfile_entry_ec, tc_stat.econ)
742 != sizeof(struct tagfile_entry))
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +0000743 {
744 logf("read error #5");
745 return false;
746 }
747
748 if (tfe.tag_length >= size)
749 {
750 logf("too small buffer");
751 return false;
752 }
753
754 if (read(tcs->idxfd[tag], buf, tfe.tag_length) !=
755 tfe.tag_length)
756 {
757 logf("read error #6");
758 return false;
759 }
760
761 buf[tfe.tag_length] = '\0';
762
763 return true;
764}
765
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000766static long check_virtual_tags(int tag, const struct index_entry *idx)
767{
768 long data = 0;
769
770 switch (tag)
771 {
Miika Pekkarinen9d9937a2007-04-12 20:14:05 +0000772 case tag_virt_length_sec:
773 data = (idx->tag_seek[tag_length]/1000) % 60;
774 break;
775
776 case tag_virt_length_min:
777 data = (idx->tag_seek[tag_length]/1000) / 60;
778 break;
779
Miika Pekkarinen5e47daa2007-04-12 20:21:56 +0000780 case tag_virt_playtime_sec:
781 data = (idx->tag_seek[tag_playtime]/1000) % 60;
782 break;
783
784 case tag_virt_playtime_min:
785 data = (idx->tag_seek[tag_playtime]/1000) / 60;
786 break;
787
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000788 case tag_virt_autoscore:
789 if (idx->tag_seek[tag_length] == 0
790 || idx->tag_seek[tag_playcount] == 0)
791 {
792 data = 0;
793 }
794 else
795 {
796 data = 100 * idx->tag_seek[tag_playtime]
797 / idx->tag_seek[tag_length]
798 / idx->tag_seek[tag_playcount];
799 }
800 break;
801
Miika Pekkarinenf5184f32007-02-25 20:41:51 +0000802 /* How many commits before the file has been added to the DB. */
803 case tag_virt_entryage:
804 data = current_tcmh.commitid - idx->tag_seek[tag_commitid] - 1;
805 break;
806
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000807 default:
808 data = idx->tag_seek[tag];
809 }
810
811 return data;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +0000812}
813
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000814long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
815{
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000816 struct index_entry idx;
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000817
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000818 if (!tc_stat.ready)
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +0000819 return false;
820
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000821 if (!tagcache_is_numeric_tag(tag))
822 return -1;
823
Miika Pekkarinendafa0d42006-07-24 15:35:46 +0000824 if (!get_index(tcs->masterfd, tcs->idx_id, &idx, true))
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +0000825 return -2;
826
827 return check_virtual_tags(tag, &idx);
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +0000828}
829
Miika Pekkarinene5059a72006-08-13 14:53:19 +0000830inline static bool str_ends_with(const char *str1, const char *str2)
831{
832 int str_len = strlen(str1);
833 int clause_len = strlen(str2);
834
835 if (clause_len > str_len)
836 return false;
837
838 return !strcasecmp(&str1[str_len - clause_len], str2);
839}
840
Miika Pekkarinenbe2eb022006-10-09 10:23:35 +0000841inline static bool str_oneof(const char *str, const char *list)
842{
843 const char *sep;
844 int l, len = strlen(str);
845
846 while (*list)
847 {
848 sep = strchr(list, '|');
849 l = sep ? (long)sep - (long)list : (int)strlen(list);
850 if ((l==len) && !strncasecmp(str, list, len))
851 return true;
852 list += sep ? l + 1 : l;
853 }
854
855 return false;
856}
857
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000858static bool check_against_clause(long numeric, const char *str,
859 const struct tagcache_search_clause *clause)
860{
Miika Pekkarinen3eb9e702006-10-05 09:49:18 +0000861 if (clause->numeric)
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000862 {
Miika Pekkarinen3eb9e702006-10-05 09:49:18 +0000863 switch (clause->type)
864 {
865 case clause_is:
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000866 return numeric == clause->numeric_data;
Miika Pekkarinen3eb9e702006-10-05 09:49:18 +0000867 case clause_is_not:
868 return numeric != clause->numeric_data;
869 case clause_gt:
870 return numeric > clause->numeric_data;
871 case clause_gteq:
872 return numeric >= clause->numeric_data;
873 case clause_lt:
874 return numeric < clause->numeric_data;
875 case clause_lteq:
876 return numeric <= clause->numeric_data;
877 default:
878 logf("Incorrect numeric tag: %d", clause->type);
879 }
880 }
881 else
882 {
883 switch (clause->type)
884 {
885 case clause_is:
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000886 return !strcasecmp(clause->str, str);
Miika Pekkarinen3eb9e702006-10-05 09:49:18 +0000887 case clause_is_not:
888 return strcasecmp(clause->str, str);
889 case clause_gt:
890 return 0>strcasecmp(clause->str, str);
891 case clause_gteq:
892 return 0>=strcasecmp(clause->str, str);
893 case clause_lt:
894 return 0<strcasecmp(clause->str, str);
895 case clause_lteq:
896 return 0<=strcasecmp(clause->str, str);
897 case clause_contains:
898 return (strcasestr(str, clause->str) != NULL);
899 case clause_not_contains:
900 return (strcasestr(str, clause->str) == NULL);
901 case clause_begins_with:
902 return (strcasestr(str, clause->str) == str);
903 case clause_not_begins_with:
Jonathan Gordon8ca99d32007-02-27 11:09:09 +0000904 return (strcasestr(str, clause->str) != str);
Miika Pekkarinen3eb9e702006-10-05 09:49:18 +0000905 case clause_ends_with:
906 return str_ends_with(str, clause->str);
907 case clause_not_ends_with:
908 return !str_ends_with(str, clause->str);
Miika Pekkarinenbe2eb022006-10-09 10:23:35 +0000909 case clause_oneof:
910 return str_oneof(str, clause->str);
Miika Pekkarinen3eb9e702006-10-05 09:49:18 +0000911
912 default:
913 logf("Incorrect tag: %d", clause->type);
914 }
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000915 }
Miika Pekkarinene5059a72006-08-13 14:53:19 +0000916
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +0000917 return false;
918}
919
Jens Arnold2597a132006-12-25 14:01:47 +0000920static bool check_clauses(struct tagcache_search *tcs,
921 struct index_entry *idx,
922 struct tagcache_search_clause **clause, int count)
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +0000923{
924 int i;
925
926#ifdef HAVE_TC_RAMCACHE
927 if (tcs->ramsearch)
928 {
929 /* Go through all conditional clauses. */
930 for (i = 0; i < count; i++)
931 {
932 struct tagfile_entry *tfe;
933 int seek;
934 char buf[256];
935 char *str = NULL;
936
937 seek = check_virtual_tags(clause[i]->tag, idx);
938
939 if (!tagcache_is_numeric_tag(clause[i]->tag))
940 {
941 if (clause[i]->tag == tag_filename)
942 {
943 retrieve(tcs, idx, tag_filename, buf, sizeof buf);
944 str = buf;
945 }
946 else
947 {
948 tfe = (struct tagfile_entry *)&hdr->tags[clause[i]->tag][seek];
949 str = tfe->tag_data;
950 }
951 }
952
953 if (!check_against_clause(seek, str, clause[i]))
954 return false;
955 }
956 }
957 else
958#endif
959 {
960 /* Check for conditions. */
961 for (i = 0; i < count; i++)
962 {
963 struct tagfile_entry tfe;
964 int seek;
965 char str[256];
966
967 seek = check_virtual_tags(clause[i]->tag, idx);
968
969 memset(str, 0, sizeof str);
970 if (!tagcache_is_numeric_tag(clause[i]->tag))
971 {
972 int fd = tcs->idxfd[clause[i]->tag];
973 lseek(fd, seek, SEEK_SET);
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +0000974 ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ);
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +0000975 if (tfe.tag_length >= (int)sizeof(str))
976 {
977 logf("Too long tag read!");
978 break ;
979 }
980
981 read(fd, str, tfe.tag_length);
982
983 /* Check if entry has been deleted. */
984 if (str[0] == '\0')
985 break;
986 }
987
988 if (!check_against_clause(seek, str, clause[i]))
989 return false;
990 }
991 }
992
993 return true;
994}
995
996bool tagcache_check_clauses(struct tagcache_search *tcs,
997 struct tagcache_search_clause **clause, int count)
998{
999 struct index_entry idx;
1000
1001 if (count == 0)
1002 return true;
1003
1004 if (!get_index(tcs->masterfd, tcs->idx_id, &idx, true))
1005 return false;
1006
1007 return check_clauses(tcs, &idx, clause, count);
1008}
1009
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001010static bool add_uniqbuf(struct tagcache_search *tcs, unsigned long id)
Miika Pekkarinene3080642006-08-25 13:22:46 +00001011{
1012 int i;
1013
1014 /* If uniq buffer is not defined we must return true for search to work. */
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001015 if (tcs->unique_list == NULL
1016 || (!tagcache_is_unique_tag(tcs->type)
1017 && !tagcache_is_numeric_tag(tcs->type)))
1018 {
Miika Pekkarinene3080642006-08-25 13:22:46 +00001019 return true;
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001020 }
Miika Pekkarinene3080642006-08-25 13:22:46 +00001021
1022 for (i = 0; i < tcs->unique_list_count; i++)
1023 {
1024 /* Return false if entry is found. */
1025 if (tcs->unique_list[i] == id)
1026 return false;
1027 }
1028
1029 if (tcs->unique_list_count < tcs->unique_list_capacity)
1030 {
1031 tcs->unique_list[i] = id;
1032 tcs->unique_list_count++;
1033 }
1034
1035 return true;
1036}
1037
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001038static bool build_lookup_list(struct tagcache_search *tcs)
1039{
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001040 struct index_entry entry;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001041 int i;
1042
1043 tcs->seek_list_count = 0;
1044
1045#ifdef HAVE_TC_RAMCACHE
1046 if (tcs->ramsearch)
1047 {
1048 int j;
1049
Miika Pekkarinencb8c7952006-07-20 12:19:31 +00001050 for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001051 {
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001052 struct index_entry *idx = &hdr->indices[i];
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001053 if (tcs->seek_list_count == SEEK_LIST_SIZE)
1054 break ;
Miika Pekkarinenf9bfd732006-04-19 18:56:59 +00001055
1056 /* Skip deleted files. */
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001057 if (idx->flag & FLAG_DELETED)
Miika Pekkarinenf9bfd732006-04-19 18:56:59 +00001058 continue;
1059
Miika Pekkarinen93ed0a72006-04-09 20:00:49 +00001060 /* Go through all filters.. */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001061 for (j = 0; j < tcs->filter_count; j++)
1062 {
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001063 if (idx->tag_seek[tcs->filter_tag[j]] != tcs->filter_seek[j])
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001064 {
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001065 break ;
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001066 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001067 }
1068
1069 if (j < tcs->filter_count)
1070 continue ;
Miika Pekkarinen93ed0a72006-04-09 20:00:49 +00001071
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001072 /* Check for conditions. */
1073 if (!check_clauses(tcs, idx, tcs->clause, tcs->clause_count))
1074 continue;
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001075
Miika Pekkarinene3080642006-08-25 13:22:46 +00001076 /* Add to the seek list if not already in uniq buffer. */
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001077 if (!add_uniqbuf(tcs, idx->tag_seek[tcs->type]))
Miika Pekkarinene3080642006-08-25 13:22:46 +00001078 continue;
1079
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001080 /* Lets add it. */
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001081 tcs->seek_list[tcs->seek_list_count] = idx->tag_seek[tcs->type];
1082 tcs->seek_flags[tcs->seek_list_count] = idx->flag;
Miika Pekkarinene3080642006-08-25 13:22:46 +00001083 tcs->seek_list_count++;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001084 }
1085
1086 tcs->seek_pos = i;
1087
1088 return tcs->seek_list_count > 0;
1089 }
1090#endif
1091
Miika Pekkarinen93ed0a72006-04-09 20:00:49 +00001092 lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) +
Miika Pekkarinencb8c7952006-07-20 12:19:31 +00001093 sizeof(struct master_header), SEEK_SET);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001094
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +00001095 while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ)
1096 == sizeof(struct index_entry))
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001097 {
Miika Pekkarinen408dfd62007-03-11 08:52:33 +00001098 if (tcs->seek_list_count == SEEK_LIST_SIZE)
1099 break ;
1100
1101 tcs->seek_pos++;
1102
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001103 /* Check if entry has been deleted. */
1104 if (entry.flag & FLAG_DELETED)
1105 continue;
1106
Miika Pekkarinen93ed0a72006-04-09 20:00:49 +00001107 /* Go through all filters.. */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001108 for (i = 0; i < tcs->filter_count; i++)
1109 {
1110 if (entry.tag_seek[tcs->filter_tag[i]] != tcs->filter_seek[i])
1111 break ;
1112 }
1113
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001114 if (i < tcs->filter_count)
1115 continue ;
1116
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001117 /* Check for conditions. */
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001118 if (!check_clauses(tcs, &entry, tcs->clause, tcs->clause_count))
1119 continue;
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001120
Miika Pekkarinene3080642006-08-25 13:22:46 +00001121 /* Add to the seek list if not already in uniq buffer. */
1122 if (!add_uniqbuf(tcs, entry.tag_seek[tcs->type]))
1123 continue;
1124
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001125 /* Lets add it. */
Miika Pekkarinene3080642006-08-25 13:22:46 +00001126 tcs->seek_list[tcs->seek_list_count] = entry.tag_seek[tcs->type];
1127 tcs->seek_flags[tcs->seek_list_count] = entry.flag;
1128 tcs->seek_list_count++;
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001129
1130 yield();
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001131 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001132
1133 return tcs->seek_list_count > 0;
1134}
1135
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001136
Miika Pekkarinencb8c7952006-07-20 12:19:31 +00001137static void remove_files(void)
1138{
1139 int i;
1140 char buf[MAX_PATH];
1141
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001142 tc_stat.ready = false;
1143 tc_stat.ramcache = false;
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +00001144 tc_stat.econ = false;
Miika Pekkarinencb8c7952006-07-20 12:19:31 +00001145 remove(TAGCACHE_FILE_MASTER);
1146 for (i = 0; i < TAG_COUNT; i++)
1147 {
1148 if (tagcache_is_numeric_tag(i))
1149 continue;
1150
1151 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i);
1152 remove(buf);
1153 }
1154}
1155
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +00001156
Miika Pekkarinenf5184f32007-02-25 20:41:51 +00001157static bool check_all_headers(void)
1158{
1159 struct master_header myhdr;
1160 struct tagcache_header tch;
1161 int tag;
1162 int fd;
1163
1164 if ( (fd = open_master_fd(&myhdr, false)) < 0)
1165 return false;
1166
1167 close(fd);
1168 if (myhdr.dirty)
1169 {
1170 logf("tagcache is dirty!");
1171 return false;
1172 }
1173
1174 memcpy(&current_tcmh, &myhdr, sizeof(struct master_header));
1175
1176 for (tag = 0; tag < TAG_COUNT; tag++)
1177 {
1178 if (tagcache_is_numeric_tag(tag))
1179 continue;
1180
1181 if ( (fd = open_tag_fd(&tch, tag, false)) < 0)
1182 return false;
1183
1184 close(fd);
1185 }
1186
1187 return true;
1188}
1189
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001190bool tagcache_search(struct tagcache_search *tcs, int tag)
1191{
Miika Pekkarinencb8c7952006-07-20 12:19:31 +00001192 struct tagcache_header tag_hdr;
1193 struct master_header master_hdr;
Miika Pekkarinen53e921c2006-04-08 08:03:51 +00001194 int i;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001195
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001196 if (tcs->initialized)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001197 tagcache_search_finish(tcs);
1198
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001199 while (read_lock)
1200 sleep(1);
1201
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001202 memset(tcs, 0, sizeof(struct tagcache_search));
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001203 if (tc_stat.commit_step > 0 || !tc_stat.ready)
Miika Pekkarinen3b313462006-04-16 17:32:54 +00001204 return false;
1205
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001206 tcs->position = sizeof(struct tagcache_header);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001207 tcs->type = tag;
1208 tcs->seek_pos = 0;
1209 tcs->seek_list_count = 0;
1210 tcs->filter_count = 0;
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001211 tcs->masterfd = -1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001212
Miika Pekkarinen53e921c2006-04-08 08:03:51 +00001213 for (i = 0; i < TAG_COUNT; i++)
1214 tcs->idxfd[i] = -1;
1215
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001216#ifndef HAVE_TC_RAMCACHE
1217 tcs->ramsearch = false;
1218#else
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001219 tcs->ramsearch = tc_stat.ramcache;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001220 if (tcs->ramsearch)
1221 {
1222 tcs->entry_count = hdr->entry_count[tcs->type];
1223 }
1224 else
1225#endif
1226 {
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001227 if (!tagcache_is_numeric_tag(tcs->type))
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001228 {
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001229 tcs->idxfd[tcs->type] = open_tag_fd(&tag_hdr, tcs->type, false);
1230 if (tcs->idxfd[tcs->type] < 0)
1231 return false;
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001232 }
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001233
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001234 /* Always open as R/W so we can pass tcs to functions that modify data also
1235 * without failing. */
1236 tcs->masterfd = open_master_fd(&master_hdr, true);
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001237
1238 if (tcs->masterfd < 0)
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001239 return false;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001240 }
1241
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001242 tcs->valid = true;
1243 tcs->initialized = true;
1244 write_lock++;
1245
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001246 return true;
1247}
1248
Miika Pekkarinene3080642006-08-25 13:22:46 +00001249void tagcache_search_set_uniqbuf(struct tagcache_search *tcs,
1250 void *buffer, long length)
1251{
1252 tcs->unique_list = (unsigned long *)buffer;
1253 tcs->unique_list_capacity = length / sizeof(*tcs->unique_list);
1254 tcs->unique_list_count = 0;
1255}
1256
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001257bool tagcache_search_add_filter(struct tagcache_search *tcs,
1258 int tag, int seek)
1259{
1260 if (tcs->filter_count == TAGCACHE_MAX_FILTERS)
1261 return false;
1262
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001263 if (!tagcache_is_unique_tag(tag) || tagcache_is_numeric_tag(tag))
1264 return false;
1265
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001266 tcs->filter_tag[tcs->filter_count] = tag;
1267 tcs->filter_seek[tcs->filter_count] = seek;
1268 tcs->filter_count++;
1269
1270 return true;
1271}
1272
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001273bool tagcache_search_add_clause(struct tagcache_search *tcs,
1274 struct tagcache_search_clause *clause)
1275{
Miika Pekkarinene3080642006-08-25 13:22:46 +00001276 int i;
1277
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001278 if (tcs->clause_count >= TAGCACHE_MAX_CLAUSES)
1279 {
1280 logf("Too many clauses");
1281 return false;
1282 }
Miika Pekkarinen53e921c2006-04-08 08:03:51 +00001283
Miika Pekkarinene3080642006-08-25 13:22:46 +00001284 /* Check if there is already a similar filter in present (filters are
1285 * much faster than clauses).
1286 */
1287 for (i = 0; i < tcs->filter_count; i++)
1288 {
1289 if (tcs->filter_tag[i] == clause->tag)
1290 return true;
1291 }
1292
Miika Pekkarinen53e921c2006-04-08 08:03:51 +00001293 if (!tagcache_is_numeric_tag(clause->tag) && tcs->idxfd[clause->tag] < 0)
1294 {
1295 char buf[MAX_PATH];
1296
1297 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, clause->tag);
1298 tcs->idxfd[clause->tag] = open(buf, O_RDONLY);
1299 }
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001300
1301 tcs->clause[tcs->clause_count] = clause;
1302 tcs->clause_count++;
1303
1304 return true;
1305}
1306
Miika Pekkarinen784112a2008-01-13 19:34:49 +00001307/* TODO: Remove this mess. */
1308#ifdef HAVE_DIRCACHE
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001309#define TAG_FILENAME_RAM(tcs) ((tcs->type == tag_filename) \
Miika Pekkarinen39c597b2008-01-13 19:13:37 +00001310 ? ((flag & FLAG_DIRCACHE) && is_dircache_intact()) : 1)
Miika Pekkarinen784112a2008-01-13 19:34:49 +00001311#else
1312#define TAG_FILENAME_RAM(tcs) (tcs->type != tag_filename)
1313#endif
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001314
1315static bool get_next(struct tagcache_search *tcs)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001316{
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001317 static char buf[TAG_MAXLEN+32];
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001318 struct tagfile_entry entry;
Miika Pekkarinen42946152006-08-30 18:18:37 +00001319 long flag = 0;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001320
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001321 if (!tcs->valid || !tc_stat.ready)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001322 return false;
1323
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001324 if (tcs->idxfd[tcs->type] < 0 && !tagcache_is_numeric_tag(tcs->type)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001325#ifdef HAVE_TC_RAMCACHE
1326 && !tcs->ramsearch
1327#endif
1328 )
1329 return false;
1330
1331 /* Relative fetch. */
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001332 if (tcs->filter_count > 0 || tcs->clause_count > 0
1333 || tagcache_is_numeric_tag(tcs->type))
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001334 {
1335 /* Check for end of list. */
1336 if (tcs->seek_list_count == 0)
1337 {
1338 /* Try to fetch more. */
1339 if (!build_lookup_list(tcs))
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001340 {
1341 tcs->valid = false;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001342 return false;
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001343 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001344 }
1345
1346 tcs->seek_list_count--;
Miika Pekkarinen42946152006-08-30 18:18:37 +00001347 flag = tcs->seek_flags[tcs->seek_list_count];
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001348
1349 /* Seek stream to the correct position and continue to direct fetch. */
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001350 if ((!tcs->ramsearch || !TAG_FILENAME_RAM(tcs))
1351 && !tagcache_is_numeric_tag(tcs->type))
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001352 {
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001353 if (!open_files(tcs, tcs->type))
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001354 return false;
1355
1356 lseek(tcs->idxfd[tcs->type], tcs->seek_list[tcs->seek_list_count], SEEK_SET);
1357 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001358 else
1359 tcs->position = tcs->seek_list[tcs->seek_list_count];
1360 }
1361
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001362 if (tagcache_is_numeric_tag(tcs->type))
1363 {
Miika Pekkarinen93bbd442006-08-25 21:13:49 +00001364 snprintf(buf, sizeof(buf), "%d", tcs->position);
1365 tcs->result_seek = tcs->position;
1366 tcs->result = buf;
1367 tcs->result_len = strlen(buf) + 1;
1368 return true;
1369 }
1370
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001371 /* Direct fetch. */
1372#ifdef HAVE_TC_RAMCACHE
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001373 if (tcs->ramsearch && TAG_FILENAME_RAM(tcs))
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001374 {
1375 struct tagfile_entry *ep;
1376
1377 if (tcs->entry_count == 0)
1378 {
1379 tcs->valid = false;
1380 return false;
1381 }
1382 tcs->entry_count--;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001383
Miika Pekkarinen42946152006-08-30 18:18:37 +00001384 tcs->result_seek = tcs->position;
Miika Pekkarinen98127652006-08-27 14:58:46 +00001385
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001386# ifdef HAVE_DIRCACHE
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001387 if (tcs->type == tag_filename)
1388 {
Kevin Ferrare011a3252007-07-20 17:06:55 +00001389 dircache_copy_path((struct dirent *)tcs->position,
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001390 buf, sizeof buf);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001391 tcs->result = buf;
1392 tcs->result_len = strlen(buf) + 1;
Miika Pekkarinen42946152006-08-30 18:18:37 +00001393 tcs->idx_id = FLAG_GET_ATTR(flag);
1394 tcs->ramresult = false;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001395
1396 return true;
1397 }
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001398# endif
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001399
1400 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position];
1401 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
1402 tcs->result = ep->tag_data;
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001403 tcs->result_len = strlen(tcs->result) + 1;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001404 tcs->idx_id = ep->idx_id;
Miika Pekkarinen42946152006-08-30 18:18:37 +00001405 tcs->ramresult = true;
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001406
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001407 return true;
1408 }
1409 else
1410#endif
1411 {
Miika Pekkarinenb89b5ba2006-10-15 11:01:18 +00001412 if (!open_files(tcs, tcs->type))
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001413 return false;
1414
1415 tcs->result_seek = lseek(tcs->idxfd[tcs->type], 0, SEEK_CUR);
Miika Pekkarinen9b9539c2007-02-13 21:51:18 +00001416 if (ecread(tcs->idxfd[tcs->type], &entry, 1,
1417 tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry))
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001418 {
1419 /* End of data. */
1420 tcs->valid = false;
1421 return false;
1422 }
1423 }
1424
1425 if (entry.tag_length > (long)sizeof(buf))
1426 {
1427 tcs->valid = false;
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001428 logf("too long tag #2");
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001429 return false;
1430 }
1431
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001432 if (read(tcs->idxfd[tcs->type], buf, entry.tag_length) != entry.tag_length)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001433 {
1434 tcs->valid = false;
Miika Pekkarinen36e30812006-09-26 11:23:18 +00001435 logf("read error #4");
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001436 return false;
1437 }
1438
1439 tcs->result = buf;
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001440 tcs->result_len = strlen(tcs->result) + 1;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001441 tcs->idx_id = entry.idx_id;
Miika Pekkarinen42946152006-08-30 18:18:37 +00001442 tcs->ramresult = false;
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001443
1444 return true;
1445}
1446
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001447bool tagcache_get_next(struct tagcache_search *tcs)
1448{
1449 while (get_next(tcs))
1450 {
1451 if (tcs->result_len > 1)
1452 return true;
1453 }
1454
1455 return false;
1456}
1457
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001458bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
Miika Pekkarinen02df5a82006-10-24 16:20:48 +00001459 int tag, char *buf, long size)
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001460{
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +00001461 struct index_entry idx;
Miika Pekkarinen58fe4de2006-04-10 10:26:24 +00001462
Miika Pekkarinen6ee82e72006-09-23 10:29:14 +00001463 *buf = '\0';
Miika Pekkarinendafa0d42006-07-24 15:35:46 +00001464 if (!get_index(tcs->masterfd, idxid, &idx, true))
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +00001465 return false;
1466
Miika Pekkarinen02df5a82006-10-24 16:20:48 +00001467 return retrieve(tcs, &idx, tag, buf, size);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001468}
1469
Miika Pekkarinenf5184f32007-02-25 20:41:51 +00001470static bool update_master_header(void)
1471{
1472 struct master_header myhdr;
1473 int fd;
1474
1475 if (!tc_stat.ready)
1476 return false;
1477
1478 if ( (fd = open_master_fd(&myhdr, true)) < 0)
1479 return false;
1480
1481 myhdr.serial = current_tcmh.serial;
1482 myhdr.commitid = current_tcmh.commitid;
1483
1484 /* Write it back */
1485 lseek(fd, 0, SEEK_SET);
1486 ecwrite(fd, &myhdr, 1, master_header_ec, tc_stat.econ);
1487 close(fd);
1488
1489#ifdef HAVE_TC_RAMCACHE
1490 if (hdr)
1491 {
1492 hdr->h.serial = current_tcmh.serial;
1493 hdr->h.commitid = current_tcmh.commitid;
1494 }
1495#endif
1496
1497 return true;
1498}
1499
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001500#if 0
Miika Pekkarinenfa893c62006-04-18 18:56:56 +00001501
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001502void tagcache_modify(struct tagcache_search *tcs, int type, const char *text)
1503{
1504 struct tagentry *entry;
1505
1506 if (tcs->type != tag_title)
1507 return ;
1508
1509 /* We will need reserve buffer for this. */
1510 if (tcs->ramcache)
1511 {
1512 struct tagfile_entry *ep;
1513
1514 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->result_seek];
1515 tcs->seek_list[tcs->seek_list_count];
1516 }
1517
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001518 entry = find_entry_ram();
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001519
1520}
1521#endif
1522
1523void tagcache_search_finish(struct tagcache_search *tcs)
1524{
Miika Pekkarinen53e921c2006-04-08 08:03:51 +00001525 int i;
1526
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001527 if (!tcs->initialized)
1528 return;
1529
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001530 if (tcs->masterfd >= 0)
1531 {
1532 close(tcs->masterfd);
1533 tcs->masterfd = -1;
1534 }
Miika Pekkarinen53e921c2006-04-08 08:03:51 +00001535
1536 for (i = 0; i < TAG_COUNT; i++)
1537 {
1538 if (tcs->idxfd[i] >= 0)
1539 {
1540 close(tcs->idxfd[i]);
1541 tcs->idxfd[i] = -1;
1542 }
1543 }
Miika Pekkarinen4c6fd0f2006-04-03 18:57:34 +00001544
1545 tcs->ramsearch = false;
1546 tcs->valid = false;
Miika Pekkarinend8ac6072006-08-02 17:39:34 +00001547 tcs->initialized = 0;
1548 if (write_lock > 0)
1549 write_lock--;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001550}
1551
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001552#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
Miika Pekkarinen70c07912006-04-03 06:00:56 +00001553static struct tagfile_entry *get_tag(const struct index_entry *entry, int tag)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001554{
1555 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]];
1556}
1557
Miika Pekkarinen70c07912006-04-03 06:00:56 +00001558static long get_tag_numeric(const struct index_entry *entry, int tag)
1559{
Miika Pekkarinene461f2e2007-09-15 22:45:08 +00001560 return check_virtual_tags(tag, entry);
Miika Pekkarinen70c07912006-04-03 06:00:56 +00001561}
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001562
Magnus Holmgren74e572c2007-03-04 19:54:49 +00001563static char* get_tag_string(const struct index_entry *entry, int tag)
1564{
1565 char* s = get_tag(entry, tag)->tag_data;
1566 return strcmp(s, UNTAGGED) ? s : NULL;
1567}
1568
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001569bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
1570{
1571 struct index_entry *entry;
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +00001572 int idx_id;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001573
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001574 if (!tc_stat.ready)
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +00001575 return false;
1576
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001577 /* Find the corresponding entry in tagcache. */
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +00001578 idx_id = find_entry_ram(filename, NULL);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001579 if (idx_id < 0 || !tc_stat.ramcache)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001580 return false;
1581
Miika Pekkarinen45dfe2a2006-07-15 17:36:25 +00001582 entry = &hdr->indices[idx_id];
1583
Magnus Holmgren74e572c2007-03-04 19:54:49 +00001584 id3->title = get_tag_string(entry, tag_title);
1585 id3->artist = get_tag_string(entry, tag_artist);
1586 id3->album = get_tag_string(entry, tag_album);
1587 id3->genre_string = get_tag_string(entry, tag_genre);
1588 id3->composer = get_tag_string(entry, tag_composer);
1589 id3->comment = get_tag_string(entry, tag_comment);
1590 id3->albumartist = get_tag_string(entry, tag_albumartist);
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001591 id3->grouping = get_tag_string(entry, tag_grouping);
Robert Kukla28530bc2007-03-04 17:30:12 +00001592
1593 id3->playcount = get_tag_numeric(entry, tag_playcount);
Robert Kukla226cb7b2007-03-26 15:08:59 +00001594 id3->rating = get_tag_numeric(entry, tag_rating);
Robert Kukla28530bc2007-03-04 17:30:12 +00001595 id3->lastplayed = get_tag_numeric(entry, tag_lastplayed);
Robert Kukla226cb7b2007-03-26 15:08:59 +00001596 id3->score = get_tag_numeric(entry, tag_virt_autoscore) / 10;
Robert Kukla28530bc2007-03-04 17:30:12 +00001597 id3->year = get_tag_numeric(entry, tag_year);
1598
Dan Evertonf4a61f02007-08-03 10:00:42 +00001599 id3->discnum = get_tag_numeric(entry, tag_discnumber);
Miika Pekkarinen70c07912006-04-03 06:00:56 +00001600 id3->tracknum = get_tag_numeric(entry, tag_tracknumber);
1601 id3->bitrate = get_tag_numeric(entry, tag_bitrate);
1602 if (id3->bitrate == 0)
1603 id3->bitrate = 1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001604
1605 return true;
1606}
1607#endif
1608
1609static inline void write_item(const char *item)
1610{
1611 int len = strlen(item) + 1;
Peter D'Hoyeb4f80fb2008-01-25 21:21:41 +00001612
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001613 data_size += len;
1614 write(cachefd, item, len);
1615}
1616
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001617static int check_if_empty(char **tag)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001618{
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001619 int length;
Peter D'Hoyeb4f80fb2008-01-25 21:21:41 +00001620
1621 if (*tag == NULL || **tag == '\0')
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001622 {
Robert Kukla28530bc2007-03-04 17:30:12 +00001623 *tag = UNTAGGED;
Linus Nielsen Feltzing41621862007-03-04 19:30:03 +00001624 return sizeof(UNTAGGED); /* Tag length */
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001625 }
Peter D'Hoyeb4f80fb2008-01-25 21:21:41 +00001626
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001627 length = strlen(*tag);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001628 if (length > TAG_MAXLEN)
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001629 {
1630 logf("over length tag: %s", *tag);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001631 length = TAG_MAXLEN;
Peter D'Hoyeb4f80fb2008-01-25 21:21:41 +00001632 (*tag)[length] = '\0';
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001633 }
Peter D'Hoyeb4f80fb2008-01-25 21:21:41 +00001634
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001635 return length + 1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001636}
1637
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001638#define ADD_TAG(entry,tag,data) \
1639 /* Adding tag */ \
1640 entry.tag_offset[tag] = offset; \
1641 entry.tag_length[tag] = check_if_empty(data); \
1642 offset += entry.tag_length[tag]
1643
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001644static void add_tagcache(char *path, unsigned long mtime
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001645#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001646 ,const struct dirent *dc
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001647#endif
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001648 )
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001649{
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001650 struct mp3entry id3;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001651 struct temp_file_entry entry;
1652 bool ret;
1653 int fd;
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001654 int idx_id = -1;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001655 char tracknumfix[3];
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001656 int offset = 0;
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001657 int path_length = strlen(path);
Dan Everton00dd1492007-06-25 11:33:21 +00001658 bool has_albumartist;
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001659 bool has_grouping;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001660
1661 if (cachefd < 0)
1662 return ;
1663
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001664 /* Check for overlength file path. */
1665 if (path_length > TAG_MAXLEN)
1666 {
1667 /* Path can't be shortened. */
Magnus Holmgren01a010f2007-03-18 09:50:53 +00001668 logf("Too long path: %s", path);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001669 return ;
1670 }
1671
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001672 /* Check if the file is supported. */
1673 if (probe_file_format(path) == AFMT_UNKNOWN)
1674 return ;
1675
1676 /* Check if the file is already cached. */
Miika Pekkarinen9cd5c3e2006-07-10 16:22:03 +00001677#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
Miika Pekkarinen39c597b2008-01-13 19:13:37 +00001678 if (tc_stat.ramcache && is_dircache_intact())
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001679 {
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001680 idx_id = find_entry_ram(path, dc);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001681 }
1682 else
1683#endif
1684 {
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +00001685 if (filenametag_fd >= 0)
1686 {
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001687 idx_id = find_entry_disk(path);
1688 }
1689 }
1690
1691 /* Check if file has been modified. */
1692 if (idx_id >= 0)
1693 {
1694 struct index_entry idx;
1695
1696 if (!get_index(-1, idx_id, &idx, true))
1697 {
1698 logf("failed to retrieve index entry");
1699 return ;
1700 }
1701
1702 if ((unsigned long)idx.tag_seek[tag_mtime] == mtime)
1703 {
1704 /* No changes to file. */
1705 return ;
1706 }
1707
1708 /* Metadata might have been changed. Delete the entry. */
1709 logf("Re-adding: %s", path);
1710 if (!delete_entry(idx_id))
1711 {
1712 logf("delete_entry failed: %d", idx_id);
1713 return ;
Miika Pekkarinen29fa15f2006-07-23 11:15:28 +00001714 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001715 }
1716
1717 fd = open(path, O_RDONLY);
1718 if (fd < 0)
1719 {
1720 logf("open fail: %s", path);
1721 return ;
1722 }
1723
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001724 memset(&id3, 0, sizeof(struct mp3entry));
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001725 memset(&entry, 0, sizeof(struct temp_file_entry));
1726 memset(&tracknumfix, 0, sizeof(tracknumfix));
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001727 ret = get_metadata(&id3, fd, path);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001728 close(fd);
1729
1730 if (!ret)
Miika Pekkarinen3f3aeb02006-03-27 10:46:09 +00001731 return ;
1732
Miika Pekkarinen6ee82e72006-09-23 10:29:14 +00001733 logf("-> %s", path);
Miika Pekkarinen9c0b54a2006-07-24 12:10:50 +00001734
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001735 /* Generate track number if missing. */
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001736 if (id3.tracknum <= 0)
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001737 {
Miika Pekkarinen35d213a2006-04-05 18:46:38 +00001738 const char *p = strrchr(path, '.');
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001739
Miika Pekkarinen35d213a2006-04-05 18:46:38 +00001740 if (p == NULL)
1741 p = &path[strlen(path)-1];
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001742
Miika Pekkarinen35d213a2006-04-05 18:46:38 +00001743 while (*p != '/')
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001744 {
Miika Pekkarinen35d213a2006-04-05 18:46:38 +00001745 if (isdigit(*p) && isdigit(*(p-1)))
1746 {
1747 tracknumfix[1] = *p--;
1748 tracknumfix[0] = *p;
1749 break;
1750 }
1751 p--;
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001752 }
Miika Pekkarinen35d213a2006-04-05 18:46:38 +00001753
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001754 if (tracknumfix[0] != '\0')
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001755 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001756 id3.tracknum = atoi(tracknumfix);
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001757 /* Set a flag to indicate track number has been generated. */
1758 entry.flag |= FLAG_TRKNUMGEN;
1759 }
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001760 else
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001761 {
1762 /* Unable to generate track number. */
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001763 id3.tracknum = -1;
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001764 }
Miika Pekkarinen44b76bc2006-03-30 12:07:32 +00001765 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001766
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001767 /* Numeric tags */
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001768 entry.tag_offset[tag_year] = id3.year;
1769 entry.tag_offset[tag_discnumber] = id3.discnum;
1770 entry.tag_offset[tag_tracknumber] = id3.tracknum;
1771 entry.tag_offset[tag_length] = id3.length;
1772 entry.tag_offset[tag_bitrate] = id3.bitrate;
Miika Pekkarinenf6039462007-12-16 21:10:26 +00001773 entry.tag_offset[tag_mtime] = mtime;
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001774
1775 /* String tags. */
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001776 has_albumartist = id3.albumartist != NULL
1777 && strlen(id3.albumartist) > 0;
1778 has_grouping = id3.grouping != NULL
1779 && strlen(id3.grouping) > 0;
Dan Everton00dd1492007-06-25 11:33:21 +00001780
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001781 ADD_TAG(entry, tag_filename, &path);
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001782 ADD_TAG(entry, tag_title, &id3.title);
1783 ADD_TAG(entry, tag_artist, &id3.artist);
1784 ADD_TAG(entry, tag_album, &id3.album);
1785 ADD_TAG(entry, tag_genre, &id3.genre_string);
1786 ADD_TAG(entry, tag_composer, &id3.composer);
1787 ADD_TAG(entry, tag_comment, &id3.comment);
Dan Everton00dd1492007-06-25 11:33:21 +00001788 if (has_albumartist)
1789 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001790 ADD_TAG(entry, tag_albumartist, &id3.albumartist);
Dan Everton00dd1492007-06-25 11:33:21 +00001791 }
1792 else
1793 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001794 ADD_TAG(entry, tag_albumartist, &id3.artist);
Dan Everton00dd1492007-06-25 11:33:21 +00001795 }
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001796 if (has_grouping)
1797 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001798 ADD_TAG(entry, tag_grouping, &id3.grouping);
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001799 }
1800 else
1801 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001802 ADD_TAG(entry, tag_grouping, &id3.title);
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001803 }
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001804 entry.data_length = offset;
1805
1806 /* Write the header */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001807 write(cachefd, &entry, sizeof(struct temp_file_entry));
Miika Pekkarinen812cbad2006-10-04 09:05:01 +00001808
1809 /* And tags also... Correct order is critical */
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001810 write_item(path);
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001811 write_item(id3.title);
1812 write_item(id3.artist);
1813 write_item(id3.album);
1814 write_item(id3.genre_string);
1815 write_item(id3.composer);
1816 write_item(id3.comment);
Dan Everton00dd1492007-06-25 11:33:21 +00001817 if (has_albumartist)
1818 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001819 write_item(id3.albumartist);
Dan Everton00dd1492007-06-25 11:33:21 +00001820 }
1821 else
1822 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001823 write_item(id3.artist);
Dan Everton00dd1492007-06-25 11:33:21 +00001824 }
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001825 if (has_grouping)
1826 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001827 write_item(id3.grouping);
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001828 }
1829 else
1830 {
Nicolas Pennequin67f50822007-10-01 20:06:21 +00001831 write_item(id3.title);
Dan Evertoneecfe9f2007-08-08 10:19:56 +00001832 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001833 total_entry_count++;
1834}
1835
Miika Pekkarinen41427102006-04-23 18:47:26 +00001836static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001837{
1838 struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
1839 int len = strlen(str)+1;
Miika Pekkarinen41427102006-04-23 18:47:26 +00001840 int i;
1841 unsigned crc32;
1842 unsigned *crcbuf = (unsigned *)&tempbuf[tempbuf_size-4];
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001843 char buf[TAG_MAXLEN+32];
Miika Pekkarinen41427102006-04-23 18:47:26 +00001844
1845 for (i = 0; str[i] != '\0' && i < (int)sizeof(buf)-1; i++)
1846 buf[i] = tolower(str[i]);
1847 buf[i] = '\0';
1848
1849 crc32 = crc_32(buf, i, 0xffffffff);
1850
1851 if (unique)
1852 {
1853 /* Check if the crc does not exist -> entry does not exist for sure. */
1854 for (i = 0; i < tempbufidx; i++)
1855 {
1856 if (crcbuf[-i] != crc32)
1857 continue;
1858
1859 if (!strcasecmp(str, index[i].str))
1860 {
Miika Pekkarinen36e30812006-09-26 11:23:18 +00001861 if (id < 0 || id >= lookup_buffer_depth)
1862 {
1863 logf("lookup buf overf.: %d", id);
1864 return false;
1865 }
Miika Pekkarinen41427102006-04-23 18:47:26 +00001866
Miika Pekkarinen36e30812006-09-26 11:23:18 +00001867 lookup[id] = &index[i];
Miika Pekkarinen41427102006-04-23 18:47:26 +00001868 return true;
1869 }
1870 }
1871 }
1872
1873 /* Insert to CRC buffer. */
1874 crcbuf[-tempbufidx] = crc32;
1875 tempbuf_left -= 4;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001876
1877 /* Insert it to the buffer. */
Miika Pekkarinen41427102006-04-23 18:47:26 +00001878 tempbuf_left -= len;
Miika Pekkarinena47bd732006-07-22 07:09:57 +00001879 if (tempbuf_left - 4 < 0 || tempbufidx >= commit_entry_count-1)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001880 return false;
1881
Miika Pekkarinen36e30812006-09-26 11:23:18 +00001882 if (id >= lookup_buffer_depth)
1883 {
1884 logf("lookup buf overf. #2: %d", id);
1885 return false;
1886 }
1887
1888 if (id >= 0)
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001889 {
Miika Pekkarinen41427102006-04-23 18:47:26 +00001890 lookup[id] = &index[tempbufidx];
1891 index[tempbufidx].idlist.id = id;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001892 }
Miika Pekkarinen41427102006-04-23 18:47:26 +00001893 else
1894 index[tempbufidx].idlist.id = -1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001895
Miika Pekkarinen41427102006-04-23 18:47:26 +00001896 index[tempbufidx].idlist.next = NULL;
1897 index[tempbufidx].idx_id = idx_id;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001898 index[tempbufidx].seek = -1;
1899 index[tempbufidx].str = &tempbuf[tempbuf_pos];
1900 memcpy(index[tempbufidx].str, str, len);
1901 tempbuf_pos += len;
1902 tempbufidx++;
1903
1904 return true;
1905}
1906
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001907static int compare(const void *p1, const void *p2)
1908{
Steve Bavin6d7f68c2007-03-10 14:34:56 +00001909 do_timed_yield();
1910
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001911 struct tempbuf_searchidx *e1 = (struct tempbuf_searchidx *)p1;
1912 struct tempbuf_searchidx *e2 = (struct tempbuf_searchidx *)p2;
1913
Steve Bavin5eb29672007-03-07 10:52:19 +00001914 if (strcmp(e1->str, UNTAGGED) == 0)
1915 {
1916 if (strcmp(e2->str, UNTAGGED) == 0)
1917 return 0;
1918 return -1;
1919 }
1920 else if (strcmp(e2->str, UNTAGGED) == 0)
1921 return 1;
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001922
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +00001923 return strncasecmp(e1->str, e2->str, TAG_MAXLEN);
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001924}
1925
1926static int tempbuf_sort(int fd)
1927{
1928 struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
1929 struct tagfile_entry fe;
1930 int i;
Miika Pekkarinen3f3aeb02006-03-27 10:46:09 +00001931 int length;
Miika Pekkarinen41427102006-04-23 18:47:26 +00001932
1933 /* Generate reverse lookup entries. */
Miika Pekkarinen36e30812006-09-26 11:23:18 +00001934 for (i = 0; i < lookup_buffer_depth; i++)
Miika Pekkarinen41427102006-04-23 18:47:26 +00001935 {
1936 struct tempbuf_id_list *idlist;
1937
1938 if (!lookup[i])
1939 continue;
1940
1941 if (lookup[i]->idlist.id == i)
1942 continue;
1943
1944 idlist = &lookup[i]->idlist;
1945 while (idlist->next != NULL)
1946 idlist = idlist->next;
1947
1948 tempbuf_left -= sizeof(struct tempbuf_id_list);
1949 if (tempbuf_left - 4 < 0)
1950 return -1;
1951
1952 idlist->next = (struct tempbuf_id_list *)&tempbuf[tempbuf_pos];
1953 if (tempbuf_pos & 0x03)
1954 {
1955 tempbuf_pos = (tempbuf_pos & ~0x03) + 0x04;
1956 tempbuf_left -= 3;
1957 idlist->next = (struct tempbuf_id_list *)&tempbuf[tempbuf_pos];
1958 }
1959 tempbuf_pos += sizeof(struct tempbuf_id_list);
1960
1961 idlist = idlist->next;
1962 idlist->id = i;
1963 idlist->next = NULL;
Steve Bavin6d7f68c2007-03-10 14:34:56 +00001964
1965 do_timed_yield();
Miika Pekkarinen41427102006-04-23 18:47:26 +00001966 }
Miika Pekkarinen7c4e0c82006-03-26 11:33:42 +00001967
1968 qsort(index, tempbufidx, sizeof(struct tempbuf_searchidx