2 Unix SMB/CIFS implementation.
3 Database interface using a file per record
4 Copyright (C) Volker Lendecke 2005
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 2 of the License, or
9 (at your option) any later version.
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.
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
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Be aware that this is just sample code that has not seen too much testing
30 /* We only support one locked record at a time -- everything else
31 * would lead to a potential deadlock anyway! */
32 struct db_record
*locked_record
;
35 struct db_locked_file
{
40 struct db_file_ctx
*parent
;
43 /* Copy from statcache.c... */
45 static uint32
fsh(const uint8
*p
, int len
)
49 for (i
=0; i
<len
; i
++) {
50 n
= ((n
<< 5) + n
) ^ (uint32
)(p
[i
]);
55 static int db_locked_file_destr(struct db_locked_file
*data
)
57 if (data
->parent
!= NULL
) {
58 data
->parent
->locked_record
= NULL
;
61 if (close(data
->fd
) != 0) {
62 DEBUG(3, ("close failed: %s\n", strerror(errno
)));
69 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
);
70 static NTSTATUS
db_file_delete(struct db_record
*rec
);
72 static struct db_record
*db_file_fetch_locked(struct db_context
*db
,
76 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
78 struct db_record
*result
;
79 struct db_locked_file
*file
;
81 SMB_STRUCT_STAT statbuf
;
85 SMB_ASSERT(ctx
->locked_record
== NULL
);
88 if (!(result
= TALLOC_P(mem_ctx
, struct db_record
))) {
89 DEBUG(0, ("talloc failed\n"));
93 if (!(file
= TALLOC_P(result
, struct db_locked_file
))) {
94 DEBUG(0, ("talloc failed\n"));
99 result
->private_data
= file
;
100 result
->store
= db_file_store
;
101 result
->delete_rec
= db_file_delete
;
103 result
->key
.dsize
= key
.dsize
;
104 result
->key
.dptr
= (uint8
*)talloc_memdup(result
, key
.dptr
, key
.dsize
);
105 if (result
->key
.dptr
== NULL
) {
106 DEBUG(0, ("talloc failed\n"));
112 file
->hash
= fsh(key
.dptr
, key
.dsize
);
113 file
->name
= hex_encode(file
, (unsigned char *)key
.dptr
, key
.dsize
);
114 if (file
->name
== NULL
) {
115 DEBUG(0, ("hex_encode failed\n"));
120 file
->path
= talloc_asprintf(file
, "%s/%2.2X/%s", ctx
->dirname
,
121 file
->hash
, file
->name
);
122 if (file
->path
== NULL
) {
123 DEBUG(0, ("talloc_asprintf failed\n"));
129 file
->fd
= open(file
->path
, O_RDWR
|O_CREAT
, 0644);
133 DEBUG(3, ("Could not open/create %s: %s\n",
134 file
->path
, strerror(errno
)));
139 talloc_set_destructor(file
, db_locked_file_destr
);
142 fl
.l_whence
= SEEK_SET
;
148 ret
= fcntl(file
->fd
, F_SETLKW
, &fl
);
149 } while ((ret
== -1) && (errno
== EINTR
));
152 DEBUG(3, ("Could not get lock on %s: %s\n",
153 file
->path
, strerror(errno
)));
158 if (sys_fstat(file
->fd
, &statbuf
) != 0) {
159 DEBUG(3, ("Could not fstat %s: %s\n",
160 file
->path
, strerror(errno
)));
165 if (statbuf
.st_nlink
== 0) {
166 /* Someone has deleted it under the lock, retry */
171 result
->value
.dsize
= 0;
172 result
->value
.dptr
= NULL
;
174 if (statbuf
.st_size
!= 0) {
175 result
->value
.dsize
= statbuf
.st_size
;
176 result
->value
.dptr
= TALLOC_ARRAY(result
, uint8
,
178 if (result
->value
.dptr
== NULL
) {
179 DEBUG(1, ("talloc failed\n"));
184 nread
= read_data(file
->fd
, (char *)result
->value
.dptr
,
185 result
->value
.dsize
);
186 if (nread
!= result
->value
.dsize
) {
187 DEBUG(3, ("read_data failed: %s\n", strerror(errno
)));
193 ctx
->locked_record
= result
;
194 file
->parent
= (struct db_file_ctx
*)talloc_reference(file
, ctx
);
199 static NTSTATUS
db_file_store_root(int fd
, TDB_DATA data
)
201 if (sys_lseek(fd
, 0, SEEK_SET
) != 0) {
202 DEBUG(0, ("sys_lseek failed: %s\n", strerror(errno
)));
203 return map_nt_error_from_unix(errno
);
206 if (write_data(fd
, (char *)data
.dptr
, data
.dsize
) != data
.dsize
) {
207 DEBUG(3, ("write_data failed: %s\n", strerror(errno
)));
208 return map_nt_error_from_unix(errno
);
211 if (sys_ftruncate(fd
, data
.dsize
) != 0) {
212 DEBUG(3, ("sys_ftruncate failed: %s\n", strerror(errno
)));
213 return map_nt_error_from_unix(errno
);
219 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
221 struct db_locked_file
*file
=
222 talloc_get_type_abort(rec
->private_data
,
223 struct db_locked_file
);
227 status
= db_file_store_root(file
->fd
, data
);
233 static NTSTATUS
db_file_delete(struct db_record
*rec
)
235 struct db_locked_file
*file
=
236 talloc_get_type_abort(rec
->private_data
,
237 struct db_locked_file
);
241 res
= unlink(file
->path
);
245 DEBUG(3, ("unlink(%s) failed: %s\n", file
->path
,
247 return map_nt_error_from_unix(errno
);
253 static int db_file_traverse(struct db_context
*db
,
254 int (*fn
)(struct db_record
*rec
,
258 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
260 TALLOC_CTX
*mem_ctx
= talloc_init("traversal %s\n", ctx
->dirname
);
265 for (i
=0; i
<256; i
++) {
266 const char *dirname
= talloc_asprintf(mem_ctx
, "%s/%2.2X",
269 struct dirent
*dirent
;
271 if (dirname
== NULL
) {
272 DEBUG(0, ("talloc failed\n"));
273 TALLOC_FREE(mem_ctx
);
277 dir
= opendir(dirname
);
279 DEBUG(3, ("Could not open dir %s: %s\n", dirname
,
281 TALLOC_FREE(mem_ctx
);
285 while ((dirent
= readdir(dir
)) != NULL
) {
288 struct db_record
*rec
;
290 if ((dirent
->d_name
[0] == '.') &&
291 ((dirent
->d_name
[1] == '\0') ||
292 ((dirent
->d_name
[1] == '.') &&
293 (dirent
->d_name
[2] == '\0')))) {
297 keyblob
= strhex_to_data_blob(mem_ctx
, dirent
->d_name
);
298 if (keyblob
.data
== NULL
) {
299 DEBUG(5, ("strhex_to_data_blob failed\n"));
303 key
.dptr
= keyblob
.data
;
304 key
.dsize
= keyblob
.length
;
306 if ((ctx
->locked_record
!= NULL
) &&
307 (key
.dsize
== ctx
->locked_record
->key
.dsize
) &&
308 (memcmp(key
.dptr
, ctx
->locked_record
->key
.dptr
,
311 if (fn(ctx
->locked_record
,
312 private_data
) != 0) {
313 TALLOC_FREE(mem_ctx
);
319 rec
= db_file_fetch_locked(db
, mem_ctx
, key
);
321 /* Someone might have deleted it */
325 if (rec
->value
.dptr
== NULL
) {
332 if (fn(rec
, private_data
) != 0) {
333 TALLOC_FREE(mem_ctx
);
343 TALLOC_FREE(mem_ctx
);
347 struct db_context
*db_open_file(TALLOC_CTX
*mem_ctx
,
348 struct messaging_context
*msg_ctx
,
350 int hash_size
, int tdb_flags
,
351 int open_flags
, mode_t mode
)
353 struct db_context
*result
= NULL
;
354 struct db_file_ctx
*ctx
;
356 if (!(result
= TALLOC_ZERO_P(mem_ctx
, struct db_context
))) {
357 DEBUG(0, ("talloc failed\n"));
361 if (!(ctx
= TALLOC_P(result
, struct db_file_ctx
))) {
362 DEBUG(0, ("talloc failed\n"));
367 result
->private_data
= ctx
;
368 result
->fetch_locked
= db_file_fetch_locked
;
369 result
->traverse
= db_file_traverse
;
370 result
->traverse_read
= db_file_traverse
;
372 ctx
->locked_record
= NULL
;
373 if (!(ctx
->dirname
= talloc_strdup(ctx
, name
))) {
374 DEBUG(0, ("talloc failed\n"));
379 if (open_flags
& O_CREAT
) {
382 mode
|= (mode
& S_IRUSR
) ? S_IXUSR
: 0;
383 mode
|= (mode
& S_IRGRP
) ? S_IXGRP
: 0;
384 mode
|= (mode
& S_IROTH
) ? S_IXOTH
: 0;
386 ret
= mkdir(name
, mode
);
387 if ((ret
!= 0) && (errno
!= EEXIST
)) {
388 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", name
, mode
,
394 for (i
=0; i
<256; i
++) {
396 path
= talloc_asprintf(result
, "%s/%2.2X", name
, i
);
398 DEBUG(0, ("asprintf failed\n"));
402 ret
= mkdir(path
, mode
);
403 if ((ret
!= 0) && (errno
!= EEXIST
)) {
404 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", path
,
405 mode
, strerror(errno
)));