diff options
author | Jason Downs <downsj@downsj.com> | 2008-11-21 21:33:39 +0000 |
---|---|---|
committer | Jason Downs <downsj@downsj.com> | 2008-11-21 21:33:39 +0000 |
commit | 10fe387708ddfba6449b9abd74cfbdf67d495465 (patch) | |
tree | 50115c0708c762940f580d081c73495bf148101a /src/gdbmstore.c | |
download | gdbm-10fe387708ddfba6449b9abd74cfbdf67d495465.tar.gz gdbm-10fe387708ddfba6449b9abd74cfbdf67d495465.tar.bz2 |
Initial revision
Diffstat (limited to 'src/gdbmstore.c')
-rw-r--r-- | src/gdbmstore.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/gdbmstore.c b/src/gdbmstore.c new file mode 100644 index 0000000..cc2bee7 --- /dev/null +++ b/src/gdbmstore.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* gdbmstore.c - Add a new key/data pair to the database. */ | ||
2 | |||
3 | /* This file is part of GDBM, the GNU data base manager. | ||
4 | Copyright (C) 1990, 1991, 1993, 2007 Free Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 3, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | /* Include system configuration before all else. */ | ||
21 | #include "autoconf.h" | ||
22 | |||
23 | #include "gdbmdefs.h" | ||
24 | #include "gdbmerrno.h" | ||
25 | |||
26 | |||
27 | /* Add a new element to the database. CONTENT is keyed by KEY. The | ||
28 | file on disk is updated to reflect the structure of the new database | ||
29 | before returning from this procedure. The FLAGS define the action to | ||
30 | take when the KEY is already in the database. The value GDBM_REPLACE | ||
31 | asks that the old data be replaced by the new CONTENT. The value | ||
32 | GDBM_INSERT asks that an error be returned and no action taken. A | ||
33 | return value of 0 means no errors. A return value of -1 means that | ||
34 | the item was not stored in the data base because the caller was not an | ||
35 | official writer. A return value of 0 means that the item was not stored | ||
36 | because the argument FLAGS was GDBM_INSERT and the KEY was already in | ||
37 | the database. */ | ||
38 | |||
39 | int | ||
40 | gdbm_store (gdbm_file_info *dbf, datum key, datum content, int flags) | ||
41 | { | ||
42 | int new_hash_val; /* The new hash value. */ | ||
43 | int elem_loc; /* The location in hash bucket. */ | ||
44 | off_t file_adr; /* The address of new space in the file. */ | ||
45 | off_t file_pos; /* The position after a lseek. */ | ||
46 | int num_bytes; /* Used for error detection. */ | ||
47 | off_t free_adr; /* For keeping track of a freed section. */ | ||
48 | int free_size; | ||
49 | int new_size; /* Used in allocating space. */ | ||
50 | char *temp; /* Used in _gdbm_findkey call. */ | ||
51 | |||
52 | |||
53 | /* First check to make sure this guy is a writer. */ | ||
54 | if (dbf->read_write == GDBM_READER) | ||
55 | { | ||
56 | gdbm_errno = GDBM_READER_CANT_STORE; | ||
57 | return -1; | ||
58 | } | ||
59 | |||
60 | /* Check for illegal data values. A NULL dptr field is illegal because | ||
61 | NULL dptr returned by a lookup procedure indicates an error. */ | ||
62 | if ((key.dptr == NULL) || (content.dptr == NULL)) | ||
63 | { | ||
64 | gdbm_errno = GDBM_ILLEGAL_DATA; | ||
65 | return -1; | ||
66 | } | ||
67 | |||
68 | /* Initialize the gdbm_errno variable. */ | ||
69 | gdbm_errno = GDBM_NO_ERROR; | ||
70 | |||
71 | /* Look for the key in the file. | ||
72 | A side effect loads the correct bucket and calculates the hash value. */ | ||
73 | elem_loc = _gdbm_findkey (dbf, key, &temp, &new_hash_val); | ||
74 | |||
75 | /* Initialize these. */ | ||
76 | file_adr = 0; | ||
77 | new_size = key.dsize + content.dsize; | ||
78 | |||
79 | /* Did we find the item? */ | ||
80 | if (elem_loc != -1) | ||
81 | { | ||
82 | if (flags == GDBM_REPLACE) | ||
83 | { | ||
84 | /* Just replace the data. */ | ||
85 | free_adr = dbf->bucket->h_table[elem_loc].data_pointer; | ||
86 | free_size = dbf->bucket->h_table[elem_loc].key_size | ||
87 | + dbf->bucket->h_table[elem_loc].data_size; | ||
88 | if (free_size != new_size) | ||
89 | { | ||
90 | _gdbm_free (dbf, free_adr, free_size); | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | /* Just reuse the same address! */ | ||
95 | file_adr = free_adr; | ||
96 | } | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | gdbm_errno = GDBM_CANNOT_REPLACE; | ||
101 | return 1; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | /* Get the file address for the new space. | ||
107 | (Current bucket's free space is first place to look.) */ | ||
108 | if (file_adr == 0) | ||
109 | { | ||
110 | file_adr = _gdbm_alloc (dbf, new_size); | ||
111 | } | ||
112 | |||
113 | /* If this is a new entry in the bucket, we need to do special things. */ | ||
114 | if (elem_loc == -1) | ||
115 | { | ||
116 | if (dbf->bucket->count == dbf->header->bucket_elems) | ||
117 | { | ||
118 | /* Split the current bucket. */ | ||
119 | _gdbm_split_bucket (dbf, new_hash_val); | ||
120 | } | ||
121 | |||
122 | /* Find space to insert into bucket and set elem_loc to that place. */ | ||
123 | elem_loc = new_hash_val % dbf->header->bucket_elems; | ||
124 | while (dbf->bucket->h_table[elem_loc].hash_value != -1) | ||
125 | { elem_loc = (elem_loc + 1) % dbf->header->bucket_elems; } | ||
126 | |||
127 | /* We now have another element in the bucket. Add the new information.*/ | ||
128 | dbf->bucket->count += 1; | ||
129 | dbf->bucket->h_table[elem_loc].hash_value = new_hash_val; | ||
130 | memcpy (dbf->bucket->h_table[elem_loc].key_start, key.dptr, | ||
131 | (SMALL < key.dsize ? SMALL : key.dsize)); | ||
132 | } | ||
133 | |||
134 | |||
135 | /* Update current bucket data pointer and sizes. */ | ||
136 | dbf->bucket->h_table[elem_loc].data_pointer = file_adr; | ||
137 | dbf->bucket->h_table[elem_loc].key_size = key.dsize; | ||
138 | dbf->bucket->h_table[elem_loc].data_size = content.dsize; | ||
139 | |||
140 | /* Write the data to the file. */ | ||
141 | file_pos = __lseek (dbf, file_adr, L_SET); | ||
142 | if (file_pos != file_adr) _gdbm_fatal (dbf, "lseek error"); | ||
143 | num_bytes = __write (dbf, key.dptr, key.dsize); | ||
144 | if (num_bytes != key.dsize) _gdbm_fatal (dbf, "write error"); | ||
145 | num_bytes = __write (dbf, content.dptr, content.dsize); | ||
146 | if (num_bytes != content.dsize) _gdbm_fatal (dbf, "write error"); | ||
147 | |||
148 | /* Current bucket has changed. */ | ||
149 | dbf->cache_entry->ca_changed = TRUE; | ||
150 | dbf->bucket_changed = TRUE; | ||
151 | |||
152 | /* Write everything that is needed to the disk. */ | ||
153 | _gdbm_end_update (dbf); | ||
154 | return 0; | ||
155 | |||
156 | } | ||