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 Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include "mdbtools.h"
20 
21 #ifdef DMALLOC
22 #include "dmalloc.h"
23 #endif
24 
25 static gint32
mdb_map_find_next0(MdbHandle * mdb,unsigned char * map,unsigned int map_sz,guint32 start_pg)26 mdb_map_find_next0(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
27 {
28 	guint32 pgnum, i, usage_bitlen;
29 	unsigned char *usage_bitmap;
30 
31 	pgnum = mdb_get_int32((char *)map, 1);
32 	usage_bitmap = map + 5;
33 	usage_bitlen = (map_sz - 5) * 8;
34 
35 	i = (start_pg >= pgnum) ? start_pg-pgnum+1 : 0;
36 	for (; i<usage_bitlen; i++) {
37 		if (usage_bitmap[i/8] & (1 << (i%8))) {
38 			return pgnum + i;
39 		}
40 	}
41 	/* didn't find anything */
42 	return 0;
43 }
44 static gint32
mdb_map_find_next1(MdbHandle * mdb,unsigned char * map,unsigned int map_sz,guint32 start_pg)45 mdb_map_find_next1(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
46 {
47 	guint32 map_ind, max_map_pgs, offset, usage_bitlen;
48 
49 	/*
50 	* start_pg will tell us where to (re)start the scan
51 	* for the next data page.  each usage_map entry points to a
52 	* 0x05 page which bitmaps (mdb->fmt->pg_size - 4) * 8 pages.
53 	*
54 	* map_ind gives us the starting usage_map entry
55 	* offset gives us a page offset into the bitmap
56 	*/
57 	usage_bitlen = (mdb->fmt->pg_size - 4) * 8;
58 	max_map_pgs = (map_sz - 1) / 4;
59 	map_ind = (start_pg + 1) / usage_bitlen;
60 	offset = (start_pg + 1) % usage_bitlen;
61 
62 	for (; map_ind<max_map_pgs; map_ind++) {
63 		unsigned char *usage_bitmap;
64 		guint32 i, map_pg;
65 
66 		if (!(map_pg = mdb_get_int32((char *)map, (map_ind*4)+1))) {
67 			continue;
68 		}
69 		if(mdb_read_alt_pg(mdb, map_pg) != mdb->fmt->pg_size) {
70 			fprintf(stderr, "Oops! didn't get a full page at %d\n", map_pg);
71 			exit(1);
72 		}
73 
74 		usage_bitmap = mdb->alt_pg_buf + 4;
75 		for (i=offset; i<usage_bitlen; i++) {
76 			if (usage_bitmap[i/8] & (1 << (i%8))) {
77 				return map_ind*usage_bitlen + i;
78 			}
79 		}
80 		offset = 0;
81 	}
82 	/* didn't find anything */
83 	return 0;
84 }
85 
86 /* returns 0 on EOF */
87 /* returns -1 on error (unsupported map type) */
88 gint32
mdb_map_find_next(MdbHandle * mdb,unsigned char * map,unsigned int map_sz,guint32 start_pg)89 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
90 {
91 	if (map[0] == 0) {
92 		return mdb_map_find_next0(mdb, map, map_sz, start_pg);
93 	} else if (map[0] == 1) {
94 		return mdb_map_find_next1(mdb, map, map_sz, start_pg);
95 	}
96 
97 	fprintf(stderr, "Warning: unrecognized usage map type: %d\n", map[0]);
98 	return -1;
99 }
100 guint32
mdb_alloc_page(MdbTableDef * table)101 mdb_alloc_page(MdbTableDef *table)
102 {
103 	printf("Allocating new page\n");
104 	return 0;
105 }
106 guint32
mdb_map_find_next_freepage(MdbTableDef * table,int row_size)107 mdb_map_find_next_freepage(MdbTableDef *table, int row_size)
108 {
109 	MdbCatalogEntry *entry = table->entry;
110 	MdbHandle *mdb = entry->mdb;
111 	guint32 pgnum;
112 	guint32 cur_pg = 0;
113 	int free_space;
114 
115 	do {
116 		pgnum = mdb_map_find_next(mdb,
117 				table->free_usage_map,
118 				table->freemap_sz, cur_pg);
119 		//printf("looking at page %d\n", pgnum);
120 		if (!pgnum) {
121 			/* allocate new page */
122 			pgnum = mdb_alloc_page(table);
123 			return pgnum;
124 		} else if (pgnum==-1) {
125 			fprintf(stderr, "Error: mdb_map_find_next_freepage error while reading maps.\n");
126 			exit(1);
127 		}
128 		cur_pg = pgnum;
129 
130 		mdb_read_pg(mdb, pgnum);
131 		free_space = mdb_pg_get_freespace(mdb);
132 
133 	} while (free_space < row_size);
134 
135 	//printf("page %d has %d bytes left\n", pgnum, free_space);
136 
137 	return pgnum;
138 }
139