1 /* MDB Tools - A library for reading MS Access database file
2  * Copyright (C) 2000 Brian Bruns
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19 
20 #include "mdbtools.h"
21 
22 #ifdef DMALLOC
23 #include "dmalloc.h"
24 #endif
25 
26 static guint32
mdb_map_find_next0(MdbHandle * mdb,unsigned char * map,unsigned int map_sz,guint32 start_pg)27 mdb_map_find_next0(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
28 {
29 	guint32 pgnum, i, usage_bitlen;
30 	unsigned char *usage_bitmap;
31 
32 	pgnum = mdb_get_int32(map, 1);
33 	usage_bitmap = map + 5;
34 	usage_bitlen = (map_sz - 5) * 8;
35 
36 	i = (start_pg >= pgnum) ? start_pg-pgnum+1 : 0;
37 	for (; i<usage_bitlen; i++) {
38 		if (usage_bitmap[i/8] & (1 << (i%8))) {
39 			return pgnum + i;
40 		}
41 	}
42 	/* didn't find anything */
43 	return 0;
44 }
45 static int
mdb_map_find_next1(MdbHandle * mdb,unsigned char * map,unsigned int map_sz,guint32 start_pg)46 mdb_map_find_next1(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
47 {
48 	guint32 map_ind, max_map_pgs, offset, usage_bitlen;
49 
50 	/*
51 	* start_pg will tell us where to (re)start the scan
52 	* for the next data page.  each usage_map entry points to a
53 	* 0x05 page which bitmaps (mdb->fmt->pg_size - 4) * 8 pages.
54 	*
55 	* map_ind gives us the starting usage_map entry
56 	* offset gives us a page offset into the bitmap
57 	*/
58 	usage_bitlen = (mdb->fmt->pg_size - 4) * 8;
59 	max_map_pgs = (map_sz - 1) / 4;
60 	map_ind = (start_pg + 1) / usage_bitlen;
61 	offset = (start_pg + 1) % usage_bitlen;
62 
63 	for (; map_ind<max_map_pgs; map_ind++) {
64 		unsigned char *usage_bitmap;
65 		guint32 i, map_pg;
66 
67 		if (!(map_pg = mdb_get_int32(map, (map_ind*4)+1))) {
68 			continue;
69 		}
70 		if(mdb_read_alt_pg(mdb, map_pg) != mdb->fmt->pg_size) {
71 			fprintf(stderr, "Oops! didn't get a full page at %d\n", map_pg);
72 			exit(1);
73 		}
74 
75 		usage_bitmap = mdb->alt_pg_buf + 4;
76 		for (i=offset; i<usage_bitlen; i++) {
77 			if (usage_bitmap[i/8] & (1 << (i%8))) {
78 				return map_ind*usage_bitlen + i;
79 			}
80 		}
81 		offset = 0;
82 	}
83 	/* didn't find anything */
84 	return 0;
85 }
86 guint32
mdb_map_find_next(MdbHandle * mdb,unsigned char * map,unsigned int map_sz,guint32 start_pg)87 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
88 {
89 	if (map[0] == 0) {
90 		return mdb_map_find_next0(mdb, map, map_sz, start_pg);
91 	} else if (map[0] == 1) {
92 		return mdb_map_find_next1(mdb, map, map_sz, start_pg);
93 	}
94 
95 	fprintf(stderr, "Warning: unrecognized usage map type: %d\n", map[0]);
96 	return -1;
97 }
98 guint32
mdb_alloc_page(MdbTableDef * table)99 mdb_alloc_page(MdbTableDef *table)
100 {
101 	printf("Allocating new page\n");
102 	return 0;
103 }
104 guint32
mdb_map_find_next_freepage(MdbTableDef * table,int row_size)105 mdb_map_find_next_freepage(MdbTableDef *table, int row_size)
106 {
107 	MdbCatalogEntry *entry = table->entry;
108 	MdbHandle *mdb = entry->mdb;
109 	guint32 pgnum;
110 	guint32 cur_pg = 0;
111 	int free_space;
112 
113 	do {
114 		pgnum = mdb_map_find_next(mdb,
115 				table->free_usage_map,
116 				table->freemap_sz, cur_pg);
117 		//printf("looking at page %d\n", pgnum);
118 		if (!pgnum) {
119 			/* allocate new page */
120 			pgnum = mdb_alloc_page(table);
121 			return pgnum;
122 		}
123 		cur_pg = pgnum;
124 
125 		mdb_read_pg(mdb, pgnum);
126 		free_space = mdb_pg_get_freespace(mdb);
127 
128 	} while (free_space < row_size);
129 
130 	//printf("page %d has %d bytes left\n", pgnum, free_space);
131 
132 	return pgnum;
133 }
134