Make database endianess independent.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12297 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2007-02-13 21:51:18 +00:00
parent 24c8da0b56
commit 9b9539c8d3
6 changed files with 288 additions and 51 deletions

View file

@ -69,6 +69,7 @@
#include "misc.h"
#include "settings.h"
#include "dircache.h"
#include "structec.h"
#ifndef __PCTOOL__
#include "atoi.h"
#include "splash.h"
@ -159,6 +160,12 @@ struct master_header {
long serial; /* Increasing counting number */
};
/* For the endianess correction */
static const char *tagfile_entry_ec = "ss";
static const char *index_entry_ec = "llllllllllllllll"; /* (1 + TAG_COUNT) * l */
static const char *tagcache_header_ec = "lll";
static const char *master_header_ec = "llll";
static long current_serial;
#ifdef HAVE_TC_RAMCACHE
@ -296,7 +303,7 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write)
}
/* Check the header. */
rc = read(fd, hdr, sizeof(struct tagcache_header));
rc = ecread(fd, hdr, 1, tagcache_header_ec, tc_stat.econ);
if (hdr->magic != TAGCACHE_MAGIC || rc != sizeof(struct tagcache_header))
{
logf("header error");
@ -399,8 +406,8 @@ static long find_entry_disk(const char *filename)
pos_history[i+1] = pos_history[i];
pos_history[0] = pos;
if (read(fd, &tfe, sizeof(struct tagfile_entry)) !=
sizeof(struct tagfile_entry))
if (ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ)
!= sizeof(struct tagfile_entry))
{
break ;
}
@ -512,8 +519,8 @@ static bool get_index(int masterfd, int idxid,
lseek(masterfd, idxid * sizeof(struct index_entry)
+ sizeof(struct master_header), SEEK_SET);
if (read(masterfd, idx, sizeof(struct index_entry)) !=
sizeof(struct index_entry))
if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("read error #3");
return false;
@ -543,8 +550,8 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
lseek(masterfd, idxid * sizeof(struct index_entry)
+ sizeof(struct master_header), SEEK_SET);
if (write(masterfd, idx, sizeof(struct index_entry)) !=
sizeof(struct index_entry))
if (ecwrite(masterfd, idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("write error #3");
logf("idxid: %d", idxid);
@ -619,8 +626,8 @@ static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx,
return false;
lseek(tcs->idxfd[tag], seek, SEEK_SET);
if (read(tcs->idxfd[tag], &tfe, sizeof(struct tagfile_entry)) !=
sizeof(struct tagfile_entry))
if (ecread(tcs->idxfd[tag], &tfe, 1, tagfile_entry_ec, tc_stat.econ)
!= sizeof(struct tagfile_entry))
{
logf("read error #5");
return false;
@ -831,7 +838,7 @@ static bool check_clauses(struct tagcache_search *tcs,
{
int fd = tcs->idxfd[clause[i]->tag];
lseek(fd, seek, SEEK_SET);
read(fd, &tfe, sizeof(struct tagfile_entry));
ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ);
if (tfe.tag_length >= (int)sizeof(str))
{
logf("Too long tag read!");
@ -952,8 +959,8 @@ static bool build_lookup_list(struct tagcache_search *tcs)
lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) +
sizeof(struct master_header), SEEK_SET);
while (read(tcs->masterfd, &entry, sizeof(struct index_entry)) ==
sizeof(struct index_entry))
while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ)
== sizeof(struct index_entry))
{
/* Check if entry has been deleted. */
if (entry.flag & FLAG_DELETED)
@ -1001,6 +1008,7 @@ static void remove_files(void)
tc_stat.ready = false;
tc_stat.ramcache = false;
tc_stat.econ = false;
remove(TAGCACHE_FILE_MASTER);
for (i = 0; i < TAG_COUNT; i++)
{
@ -1026,8 +1034,20 @@ static int open_master_fd(struct master_header *hdr, bool write)
return fd;
}
tc_stat.econ = false;
/* Check the header. */
rc = read(fd, hdr, sizeof(struct master_header));
if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
{
/* Success. */
return fd;
}
/* Trying to read again, this time with endianess correction enabled. */
lseek(fd, 0, SEEK_SET);
rc = ecread(fd, hdr, 1, master_header_ec, true);
if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
{
logf("header error");
@ -1035,6 +1055,8 @@ static int open_master_fd(struct master_header *hdr, bool write)
close(fd);
return -2;
}
tc_stat.econ = true;
return fd;
}
@ -1260,8 +1282,8 @@ static bool get_next(struct tagcache_search *tcs)
return false;
tcs->result_seek = lseek(tcs->idxfd[tcs->type], 0, SEEK_CUR);
if (read(tcs->idxfd[tcs->type], &entry, sizeof(struct tagfile_entry)) !=
sizeof(struct tagfile_entry))
if (ecread(tcs->idxfd[tcs->type], &entry, 1,
tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry))
{
/* End of data. */
tcs->valid = false;
@ -1739,7 +1761,7 @@ static int tempbuf_sort(int fd)
}
#endif
if (write(fd, &fe, sizeof(struct tagfile_entry)) !=
if (ecwrite(fd, &fe, 1, tagfile_entry_ec, tc_stat.econ) !=
sizeof(struct tagfile_entry))
{
logf("tempbuf_sort: write error #1");
@ -1833,8 +1855,8 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
{
int loc = lseek(masterfd, 0, SEEK_CUR);
if (read(masterfd, &idx, sizeof(struct index_entry)) !=
sizeof(struct index_entry))
if (ecread(masterfd, &idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("read fail #2");
close(masterfd);
@ -1852,8 +1874,8 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
/* Write back the updated index. */
lseek(masterfd, loc, SEEK_SET);
if (write(masterfd, &idx, sizeof(struct index_entry)) !=
sizeof(struct index_entry))
if (ecwrite(masterfd, &idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("write fail");
close(masterfd);
@ -1977,7 +1999,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
int loc = lseek(fd, 0, SEEK_CUR);
bool ret;
if (read(fd, &entry, sizeof(struct tagfile_entry))
if (ecread(fd, &entry, 1, tagfile_entry_ec, tc_stat.econ)
!= sizeof(struct tagfile_entry))
{
logf("read error #7");
@ -2041,8 +2063,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
tch.entry_count = 0;
tch.datasize = 0;
if (write(fd, &tch, sizeof(struct tagcache_header)) !=
sizeof(struct tagcache_header))
if (ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ)
!= sizeof(struct tagcache_header))
{
logf("header write failed");
close(fd);
@ -2071,7 +2093,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
tcmh.tch = *h;
tcmh.tch.entry_count = 0;
tcmh.tch.datasize = 0;
write(masterfd, &tcmh, sizeof(struct master_header));
ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ);
init = true;
masterfd_pos = lseek(masterfd, 0, SEEK_CUR);
current_serial = 0;
@ -2084,7 +2106,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
*/
init = false;
if (read(masterfd, &tcmh, sizeof(struct master_header)) !=
if (ecread(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ) !=
sizeof(struct master_header) || tcmh.tch.magic != TAGCACHE_MAGIC)
{
logf("header error");
@ -2125,7 +2147,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
sizeof(struct temp_file_entry))
{
logf("read fail #1");
logf("read fail #3");
error = true;
goto error_exit;
}
@ -2142,7 +2164,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
if (read(tmpfd, buf, entry.tag_length[index_type]) !=
entry.tag_length[index_type])
{
logf("read fail #3");
logf("read fail #4");
error = true;
goto error_exit;
}
@ -2184,10 +2206,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
idxbuf_pos = MIN(tcmh.tch.entry_count - i, IDX_BUF_DEPTH);
if (read(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
(int)sizeof(struct index_entry)*idxbuf_pos)
if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ)
!= (int)sizeof(struct index_entry)*idxbuf_pos)
{
logf("read fail #2");
logf("read fail #5");
error = true;
goto error_exit ;
}
@ -2217,7 +2239,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
}
/* Write back the updated index. */
if (write(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
if (ecwrite(masterfd, idxbuf, idxbuf_pos,
index_entry_ec, tc_stat.econ) !=
(int)sizeof(struct index_entry)*idxbuf_pos)
{
logf("write fail");
@ -2249,10 +2272,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
{
int loc = lseek(masterfd, 0, SEEK_CUR);
if (read(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
(int)sizeof(struct index_entry)*idxbuf_pos)
if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ)
!= (int)sizeof(struct index_entry)*idxbuf_pos)
{
logf("read fail #2");
logf("read fail #6");
error = true;
break ;
}
@ -2270,7 +2293,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
sizeof(struct temp_file_entry))
{
logf("read fail #1");
logf("read fail #7");
error = true;
break ;
}
@ -2289,7 +2312,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
if (read(tmpfd, buf, entry.tag_length[index_type]) !=
entry.tag_length[index_type])
{
logf("read fail #3");
logf("read fail #8");
logf("offset=0x%02x", entry.tag_offset[index_type]);
logf("length=0x%02x", entry.tag_length[index_type]);
error = true;
@ -2300,7 +2323,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
idxbuf[j].tag_seek[index_type] = lseek(fd, 0, SEEK_CUR);
fe.tag_length = entry.tag_length[index_type];
fe.idx_id = tcmh.tch.entry_count + i + j;
write(fd, &fe, sizeof(struct tagfile_entry));
ecwrite(fd, &fe, 1, tagfile_entry_ec, tc_stat.econ);
write(fd, buf, fe.tag_length);
tempbufidx++;
@ -2322,7 +2345,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
}
/* Write index. */
if (write(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
if (ecwrite(masterfd, idxbuf, idxbuf_pos,
index_entry_ec, tc_stat.econ) !=
(int)sizeof(struct index_entry)*idxbuf_pos)
{
logf("tagcache: write fail #4");
@ -2339,7 +2363,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
tch.entry_count = tempbufidx;
tch.datasize = lseek(fd, 0, SEEK_END) - sizeof(struct tagcache_header);
lseek(fd, 0, SEEK_SET);
write(fd, &tch, sizeof(struct tagcache_header));
ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ);
if (index_type != tag_filename)
h->datasize += tch.datasize;
@ -2495,7 +2519,7 @@ static bool commit(void)
+ tch.datasize;
lseek(masterfd, 0, SEEK_SET);
write(masterfd, &tcmh, sizeof(struct master_header));
ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ);
close(masterfd);
logf("tagcache committed");
@ -2570,7 +2594,7 @@ static bool update_current_serial(long serial)
/* Write it back */
lseek(fd, 0, SEEK_SET);
write(fd, &myhdr, sizeof(struct master_header));
ecwrite(fd, &myhdr, 1, master_header_ec, tc_stat.econ);
close(fd);
return true;
@ -2872,14 +2896,14 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
else
{
lseek(tcs->masterfd, 0, SEEK_SET);
read(tcs->masterfd, &myhdr, sizeof(struct master_header));
ecread(tcs->masterfd, &myhdr, 1, master_header_ec, tc_stat.econ);
}
write(clfd, "## Changelog version 1\n", 23);
for (i = 0; i < myhdr.tch.entry_count; i++)
{
if (read(tcs->masterfd, &idx, sizeof(struct index_entry))
if (ecread(tcs->masterfd, &idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("read error #9");
@ -2943,7 +2967,7 @@ static bool delete_entry(long idx_id)
return false;
lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR);
if (read(fd, &myidx, sizeof(struct index_entry))
if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("delete_entry(): read error");
@ -2953,7 +2977,7 @@ static bool delete_entry(long idx_id)
myidx.flag |= FLAG_DELETED;
lseek(fd, -sizeof(struct index_entry), SEEK_CUR);
if (write(fd, &myidx, sizeof(struct index_entry))
if (ecwrite(fd, &myidx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("delete_entry(): write_error");
@ -2968,7 +2992,7 @@ static bool delete_entry(long idx_id)
lseek(fd, sizeof(struct master_header), SEEK_SET);
for (i = 0; i < myhdr.tch.entry_count; i++)
{
if (read(fd, &idx, sizeof(struct index_entry))
if (ecread(fd, &idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("delete_entry(): read error #2");
@ -3190,7 +3214,7 @@ static bool load_tagcache(void)
return false;
}
if (read(fd, &hdr->h, sizeof(struct master_header))
if (ecread(fd, &hdr->h, 1, master_header_ec, tc_stat.econ)
!= sizeof(struct master_header)
|| hdr->h.tch.magic != TAGCACHE_MAGIC)
{
@ -3203,7 +3227,7 @@ static bool load_tagcache(void)
/* Load the master index table. */
for (i = 0; i < hdr->h.tch.entry_count; i++)
{
rc = read(fd, idx, sizeof(struct index_entry));
rc = ecread(fd, idx, 1, index_entry_ec, tc_stat.econ);
if (rc != sizeof(struct index_entry))
{
logf("read error #10");
@ -3262,7 +3286,7 @@ static bool load_tagcache(void)
fe = (struct tagfile_entry *)p;
pos = lseek(fd, 0, SEEK_CUR);
rc = read(fd, fe, sizeof(struct tagfile_entry));
rc = ecread(fd, fe, 1, tagfile_entry_ec, tc_stat.econ);
if (rc != sizeof(struct tagfile_entry))
{
/* End of lookup table. */
@ -3413,7 +3437,7 @@ static bool check_deleted_files(void)
}
lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
while (read(fd, &tfe, sizeof(struct tagfile_entry))
while (ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ)
== sizeof(struct tagfile_entry)
#ifndef __PCTOOL__
&& !check_event_queue()
@ -3443,7 +3467,7 @@ static bool check_deleted_files(void)
if (testfd < 0)
{
logf("Entry no longer valid.");
logf("-> %s", buf);
logf("-> %s / %d", buf, tfe.tag_length);
delete_entry(tfe.idx_id);
}
close(testfd);

View file

@ -88,6 +88,7 @@ struct tagcache_stat {
bool ready; /* Is tagcache ready to be used? */
bool ramcache; /* Is tagcache loaded in ram? */
bool commit_delayed; /* Has commit been delayed until next reboot? */
bool econ; /* Is endianess correction enabled? */
int commit_step; /* Commit progress */
int ramcache_allocated; /* Has ram been allocated for ramcache? */
int ramcache_used; /* How much ram has been really used */

View file

@ -53,6 +53,7 @@ common/strncmp.c
common/strncpy.c
common/strrchr.c
common/strtok.c
common/structec.c
common/timefuncs.c
common/unicode.c

179
firmware/common/structec.c Normal file
View file

@ -0,0 +1,179 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 by Miika Pekkarinen
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <string.h>
#include "structec.h"
#include "system.h"
#include "file.h"
#define MAX_STRUCT_SIZE 128
/**
* Convert the struct endianess with the instructions provided.
*
* For example:
* struct test {
* long par1;
* short par2;
* short par3;
* };
*
* structec_convert(instance_of_test, "lss", sizeof(struct test), true);
*
* Structures to be converted must be properly padded.
*
* @param structure Pointer to the struct being converted.
* @param ecinst Instructions how to do the endianess conversion.
* @param count Number of structures to write
* @param enable Conversion is not made unless this is true.
*/
void structec_convert(void *structure, const char *ecinst,
long count, bool enable)
{
const char *ecinst_ring = ecinst;
char *buf = (char *)structure;
if (!enable)
return;
while (count > 0)
{
switch (*ecinst_ring)
{
/* Swap nothing. */
case 'c':
{
buf++;
break;
}
/* Swap 2 bytes. */
case 's':
{
unsigned short *data = (unsigned short *)buf;
*data = SWAP_16(*data);
buf += 2;
break;
}
/* Swap 4 bytes. */
case 'l':
{
unsigned long *data = (unsigned long *)buf;
*data = SWAP_32(*data);
buf += 4;
break;
}
/* This should be never reached. */
default:
break;
}
ecinst_ring++;
if (*ecinst_ring == '\0')
{
ecinst_ring = ecinst;
count--;
}
}
}
/**
* Determines the size of a struct in bytes by using endianess correction
* string format.
*
* @param ecinst endianess correction string.
* @return length of the struct in bytes.
*/
size_t structec_size(const char *ecinst)
{
size_t size = 0;
do
{
switch (*ecinst)
{
case 'c': size += 1; break;
case 's': size += 2; break;
case 'l': size += 4; break;
default: break;
}
} while (*(++ecinst) != '\0');
return size;
}
/**
* Reads endianess corrected structure members from the given file.
*
* @param fd file descriptor of the file being read.
* @param buf endianess corrected data is placed here.
* @param scount the number of struct members to read.
* @param ecinst endianess correction string.
* @param ec if true, endianess correction is enabled.
*/
ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec)
{
ssize_t ret;
size_t member_size = structec_size(ecinst);
ret = read(fd, buf, scount * member_size);
structec_convert(buf, ecinst, scount, ec);
return ret;
}
/**
* Writes endianess corrected structure members to the given file.
*
* @param fd file descriptor of the file being written to.
* @param buf endianess corrected data is read here.
* @param scount the number of struct members to write.
* @param ecinst endianess correction string.
* @param ec if true, endianess correction is enabled.
*/
ssize_t ecwrite(int fd, const void *buf, size_t scount,
const char *ecinst, bool ec)
{
char tmp[MAX_STRUCT_SIZE];
size_t member_size = structec_size(ecinst);
if (ec)
{
const char *p = (const char *)buf;
int maxamount = (int)(MAX_STRUCT_SIZE / member_size);
int i;
for (i = 0; i < (long)scount; i += maxamount)
{
long amount = MIN((int)scount-i, maxamount);
memcpy(tmp, p, member_size * amount);
structec_convert(tmp, ecinst, amount, true);
write(fd, tmp, amount * member_size);
p += member_size * amount;
}
return scount * member_size;
}
return write(fd, buf, scount * member_size);
}

View file

@ -0,0 +1,31 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 by Miika Pekkarinen
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _STRUCTEC_H
#define _STRUCTEC_H
#include <sys/types.h>
#include <stdbool.h>
void structec_convert(void *structure, const char *ecinst,
long count, bool enable);
ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec);
ssize_t ecwrite(int fd, const void *buf, size_t scount, const char *ecinst, bool ec);
#endif

View file

@ -41,7 +41,8 @@ ipod_fw: ipod_fw.c
database: database.c ../apps/tagcache.c ../apps/metadata.c \
../firmware/id3.c ../firmware/common/unicode.c \
../firmware/common/crc32.c ../uisimulator/common/io.c \
../firmware/mp3data.c ../firmware/logf.c ../firmware/replaygain.c
../firmware/mp3data.c ../firmware/logf.c ../firmware/replaygain.c \
../firmware/common/structec.c
$(SILENT)$(CC) -g -I../firmware/export -iquote ../firmware/include \
-D__PCTOOL__ -DHAVE_TAGCACHE -DROCKBOX_HAS_LOGF -DSIMULATOR \
-DCONFIG_CODEC=1 -ldl -I../apps $+ -o $@