14 findFreeSpace(FDB *db, size_t length) {
15 FDBFreeSpace *ptr = db->space;
17 while(ptr && ptr - db->space < db->listcur) {
18 if ( ptr->length >= length )
27 cmpFS(const void* a, const void* b) {
28 if ( ((FDBFreeSpace*)a)->offset == ((FDBFreeSpace*)b)->offset )
30 return ( ((FDBFreeSpace*)a)->offset > ((FDBFreeSpace*)b)->offset ) ? 1 : -1;
34 FDBVacuumFreeSpace(FDB *db) {
35 FDBFreeSpace *ptr=db->space+1, *ok=db->space;
36 if ( db->listcur < 2 )
39 qsort( db->space, db->listcur, sizeof(FDBFreeSpace), cmpFS);
41 while( ptr - db->space < db->listcur ) {
42 tassert( ok->offset + ok->length <= ptr->offset );
43 if ( ok->offset + ok->length == ptr->offset || ptr->length==0 ) {
44 ok->length += ptr->length;
48 memcpy(ok, ptr, sizeof(FDBFreeSpace));
53 db->listcur = ok - db->space + 1;
57 FDBOpen(FDB *db, char *file, int readonly) {
61 memset(db, 0, sizeof(FDB));
65 db->fd = open(file, O_RDONLY | O_SHLOCK);
67 db->fd = open(file, O_CREAT | O_RDWR | O_EXLOCK, 0666);
71 memset(db, 0, sizeof(FDB));
72 tlog(TL_CRIT,"FDBOpen: open failed: %s", strerror(errno));
76 rc = read(db->fd, &header, sizeof(FDBHeader));
80 tlog(TL_CRIT,"FDBOpen: read failed: %s", strerror(errno));
83 memset(&header, 0, sizeof(FDBHeader));
84 } else if ( rc != sizeof(FDBHeader) ) {
86 tlog(TL_CRIT,"FDBOpen: header fault: %d bytes only", rc);
88 } else if ( header.isopened ) {
90 tlog(TL_CRIT,"FDBOpen: file wasn't closed correctly");
95 if ( !db->readonly ) {
96 if ( header.freespace ) {
97 db->listlen = db->listcur = (header.lenfreespace / sizeof(FDBFreeSpace));
98 db->space = (FDBFreeSpace*)tmalloc( header.lenfreespace + sizeof(FDBFreeSpace) );
100 if ( lseek(db->fd, header.freespace, SEEK_SET)!=header.freespace ||
101 read( db->fd, db->space, header.lenfreespace ) != header.lenfreespace ) {
103 tlog(TL_CRIT,"FDBOpen: free space read failed: %s", strerror(errno));
108 db->space = (FDBFreeSpace*)tmalloc( db->listlen*sizeof(FDBFreeSpace) );
111 header.freespace = 0;
112 header.lenfreespace = 0;
115 if ( lseek(db->fd, 0, SEEK_SET)!=0 || write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) ) {
117 if ( db->space ) tfree( db->space );
118 tlog(TL_CRIT,"FDBOpen: can't modify header: %s", strerror(errno));
129 if ( !db->readonly) {
132 memset(&header,0,sizeof(FDBHeader));
138 header.lenfreespace = sizeof(FDBFreeSpace)*db->listcur;
139 ptr = findFreeSpace( db, header.lenfreespace );
142 header.freespace = ptr->offset;
143 if ( lseek(db->fd, ptr->offset, SEEK_SET) != ptr->offset )
144 tlog(TL_CRIT|TL_EXIT,"FDBClose: lseek failed: %s", strerror(errno));
146 if ( (header.freespace = lseek(db->fd, 0, SEEK_END)) < 0 )
147 tlog(TL_CRIT|TL_EXIT,"FDBClose: lseek failed: %s", strerror(errno));
150 if ( write(db->fd, db->space, header.lenfreespace) != header.lenfreespace )
151 tlog(TL_CRIT|TL_EXIT,"FDBClose: write failed: %s", strerror(errno));
156 if ( lseek(db->fd,0,SEEK_SET)!=0 || write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) )
157 tlog(TL_CRIT|TL_EXIT,"FDBClose: header write failed: %s", strerror(errno));
169 readLen(FDB *db, off_t offset, size_t *size) {
170 if ( lseek(db->fd,offset,SEEK_SET)!=offset)
173 if ( read(db->fd,size,sizeof(size_t)) != sizeof(size_t) )
180 FDBDelete(FDB *db, off_t offset, size_t length) {
185 if ( readLen(db, offset, &length) != FDB_OK )
188 if ( db->listcur >= db->listlen ) {
190 db->space = (FDBFreeSpace*) trealloc( db->space, db->listlen * sizeof(FDBFreeSpace) );
193 db->space[ db->listcur ].offset=offset;
194 db->space[ db->listcur ].length=length;
203 FDBGet(FDB *db, off_t offset, size_t length, FDBRecord **record) {
212 if ( readLen(db, offset, &length) != FDB_OK )
215 *record = (FDBRecord*)tmalloc( length );
217 if ( lseek(db->fd,offset,SEEK_SET)!=offset)
220 if ( (rc=read(db->fd,*record,length)) != length ) {
221 (*record)->length = rc;
222 tlog(TL_CRIT,"FDBGet: read (%d bytes) less than needed (%d bytes): %s", rc, length, strerror(errno));
223 return FDB_INCORRECT;
226 if ( (*record)->length != length ) {
227 tlog(TL_ALARM, "FDBGet: wrong length in opts: %d bytes and %d bytes really", length, (*record)->length);
228 if ( (*record)->length > length ) {
229 rc = (*record)->length;
231 return FDBGet(db, offset, rc, record);
240 FDBPut(FDB *db, FDBRecord *record, off_t *offset ) {
246 ptr = findFreeSpace( db, record->length );
248 *offset = ptr->offset;
249 ptr->length -= record->length;
250 if ( ptr->length == 0 )
252 if ( lseek(db->fd, *offset, SEEK_SET) != *offset )
253 tlog(TL_CRIT|TL_EXIT,"FDBPut: lseek failed: %s", strerror(errno));
255 if ( (*offset = lseek(db->fd, 0, SEEK_END)) < 0 )
256 tlog(TL_CRIT|TL_EXIT,"FDBPut: lseek failed: %s", strerror(errno));
259 if ( write(db->fd, record, record->length) != record->length )
260 tlog(TL_CRIT|TL_EXIT,"FDBPut: write lseek failed: %s", strerror(errno));