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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "dbwrap/dbwrap.h"
22 #include "dbwrap/dbwrap_file.h"
23 #include "dbwrap/dbwrap_private.h"
24 #include "lib/util/tdb_wrap.h"
29 /* We only support one locked record at a time -- everything else
30 * would lead to a potential deadlock anyway! */
31 struct db_record
*locked_record
;
34 struct db_locked_file
{
39 struct db_file_ctx
*parent
;
42 /* Copy from statcache.c... */
44 static uint32
fsh(const uint8
*p
, int len
)
48 for (i
=0; i
<len
; i
++) {
49 n
= ((n
<< 5) + n
) ^ (uint32
)(p
[i
]);
54 static int db_locked_file_destr(struct db_locked_file
*data
)
56 if (data
->parent
!= NULL
) {
57 data
->parent
->locked_record
= NULL
;
60 if (close(data
->fd
) != 0) {
61 DEBUG(3, ("close failed: %s\n", strerror(errno
)));
68 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
);
69 static NTSTATUS
db_file_delete(struct db_record
*rec
);
71 static struct db_record
*db_file_fetch_locked(struct db_context
*db
,
75 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
77 struct db_record
*result
;
78 struct db_locked_file
*file
;
80 SMB_STRUCT_STAT statbuf
;
83 SMB_ASSERT(ctx
->locked_record
== NULL
);
86 if (!(result
= talloc(mem_ctx
, struct db_record
))) {
87 DEBUG(0, ("talloc failed\n"));
91 if (!(file
= talloc(result
, struct db_locked_file
))) {
92 DEBUG(0, ("talloc failed\n"));
97 result
->private_data
= file
;
98 result
->store
= db_file_store
;
99 result
->delete_rec
= db_file_delete
;
101 result
->key
.dsize
= key
.dsize
;
102 result
->key
.dptr
= (uint8
*)talloc_memdup(result
, key
.dptr
, key
.dsize
);
103 if (result
->key
.dptr
== NULL
) {
104 DEBUG(0, ("talloc failed\n"));
110 file
->hash
= fsh(key
.dptr
, key
.dsize
);
111 file
->name
= hex_encode_talloc(file
, (unsigned char *)key
.dptr
, key
.dsize
);
112 if (file
->name
== NULL
) {
113 DEBUG(0, ("hex_encode failed\n"));
118 file
->path
= talloc_asprintf(file
, "%s/%2.2X/%s", ctx
->dirname
,
119 file
->hash
, file
->name
);
120 if (file
->path
== NULL
) {
121 DEBUG(0, ("talloc_asprintf failed\n"));
127 file
->fd
= open(file
->path
, O_RDWR
|O_CREAT
, 0644);
131 DEBUG(3, ("Could not open/create %s: %s\n",
132 file
->path
, strerror(errno
)));
137 talloc_set_destructor(file
, db_locked_file_destr
);
140 fl
.l_whence
= SEEK_SET
;
146 ret
= fcntl(file
->fd
, F_SETLKW
, &fl
);
147 } while ((ret
== -1) && (errno
== EINTR
));
150 DEBUG(3, ("Could not get lock on %s: %s\n",
151 file
->path
, strerror(errno
)));
156 if (sys_fstat(file
->fd
, &statbuf
, false) != 0) {
157 DEBUG(3, ("Could not fstat %s: %s\n",
158 file
->path
, strerror(errno
)));
163 if (statbuf
.st_ex_nlink
== 0) {
164 /* Someone has deleted it under the lock, retry */
169 result
->value
.dsize
= 0;
170 result
->value
.dptr
= NULL
;
172 if (statbuf
.st_ex_size
!= 0) {
175 result
->value
.dsize
= statbuf
.st_ex_size
;
176 result
->value
.dptr
= talloc_array(result
, uint8
,
178 if (result
->value
.dptr
== NULL
) {
179 DEBUG(1, ("talloc failed\n"));
184 status
= read_data(file
->fd
, (char *)result
->value
.dptr
,
185 result
->value
.dsize
);
186 if (!NT_STATUS_IS_OK(status
)) {
187 DEBUG(3, ("read_data failed: %s\n",
194 ctx
->locked_record
= result
;
195 file
->parent
= (struct db_file_ctx
*)talloc_reference(file
, ctx
);
200 static NTSTATUS
db_file_store_root(int fd
, TDB_DATA data
)
202 if (sys_lseek(fd
, 0, SEEK_SET
) != 0) {
203 DEBUG(0, ("sys_lseek failed: %s\n", strerror(errno
)));
204 return map_nt_error_from_unix(errno
);
207 if (write_data(fd
, (char *)data
.dptr
, data
.dsize
) != data
.dsize
) {
208 DEBUG(3, ("write_data failed: %s\n", strerror(errno
)));
209 return map_nt_error_from_unix(errno
);
212 if (sys_ftruncate(fd
, data
.dsize
) != 0) {
213 DEBUG(3, ("sys_ftruncate failed: %s\n", strerror(errno
)));
214 return map_nt_error_from_unix(errno
);
220 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
222 struct db_locked_file
*file
=
223 talloc_get_type_abort(rec
->private_data
,
224 struct db_locked_file
);
228 status
= db_file_store_root(file
->fd
, data
);
234 static NTSTATUS
db_file_delete(struct db_record
*rec
)
236 struct db_locked_file
*file
=
237 talloc_get_type_abort(rec
->private_data
,
238 struct db_locked_file
);
242 res
= unlink(file
->path
);
246 DEBUG(3, ("unlink(%s) failed: %s\n", file
->path
,
248 return map_nt_error_from_unix(errno
);
254 static int db_file_traverse(struct db_context
*db
,
255 int (*fn
)(struct db_record
*rec
,
259 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
261 TALLOC_CTX
*mem_ctx
= talloc_init("traversal %s\n", ctx
->dirname
);
266 for (i
=0; i
<256; i
++) {
267 const char *dirname
= talloc_asprintf(mem_ctx
, "%s/%2.2X",
270 struct dirent
*dirent
;
272 if (dirname
== NULL
) {
273 DEBUG(0, ("talloc failed\n"));
274 TALLOC_FREE(mem_ctx
);
278 dir
= opendir(dirname
);
280 DEBUG(3, ("Could not open dir %s: %s\n", dirname
,
282 TALLOC_FREE(mem_ctx
);
286 while ((dirent
= readdir(dir
)) != NULL
) {
289 struct db_record
*rec
;
291 if ((dirent
->d_name
[0] == '.') &&
292 ((dirent
->d_name
[1] == '\0') ||
293 ((dirent
->d_name
[1] == '.') &&
294 (dirent
->d_name
[2] == '\0')))) {
298 keyblob
= strhex_to_data_blob(mem_ctx
, dirent
->d_name
);
299 if (keyblob
.data
== NULL
) {
300 DEBUG(5, ("strhex_to_data_blob failed\n"));
304 key
.dptr
= keyblob
.data
;
305 key
.dsize
= keyblob
.length
;
307 if ((ctx
->locked_record
!= NULL
) &&
308 (key
.dsize
== ctx
->locked_record
->key
.dsize
) &&
309 (memcmp(key
.dptr
, ctx
->locked_record
->key
.dptr
,
312 if (fn(ctx
->locked_record
,
313 private_data
) != 0) {
314 TALLOC_FREE(mem_ctx
);
320 rec
= db_file_fetch_locked(db
, mem_ctx
, key
);
322 /* Someone might have deleted it */
326 if (rec
->value
.dptr
== NULL
) {
333 if (fn(rec
, private_data
) != 0) {
334 TALLOC_FREE(mem_ctx
);
344 TALLOC_FREE(mem_ctx
);
348 struct db_context
*db_open_file(TALLOC_CTX
*mem_ctx
,
349 struct messaging_context
*msg_ctx
,
351 int hash_size
, int tdb_flags
,
352 int open_flags
, mode_t mode
)
354 struct db_context
*result
= NULL
;
355 struct db_file_ctx
*ctx
;
357 if (!(result
= talloc_zero(mem_ctx
, struct db_context
))) {
358 DEBUG(0, ("talloc failed\n"));
362 if (!(ctx
= talloc(result
, struct db_file_ctx
))) {
363 DEBUG(0, ("talloc failed\n"));
368 result
->private_data
= ctx
;
369 result
->fetch_locked
= db_file_fetch_locked
;
370 result
->traverse
= db_file_traverse
;
371 result
->traverse_read
= db_file_traverse
;
372 result
->persistent
= ((tdb_flags
& TDB_CLEAR_IF_FIRST
) == 0);
374 ctx
->locked_record
= NULL
;
375 if (!(ctx
->dirname
= talloc_strdup(ctx
, name
))) {
376 DEBUG(0, ("talloc failed\n"));
381 if (open_flags
& O_CREAT
) {
384 mode
|= (mode
& S_IRUSR
) ? S_IXUSR
: 0;
385 mode
|= (mode
& S_IRGRP
) ? S_IXGRP
: 0;
386 mode
|= (mode
& S_IROTH
) ? S_IXOTH
: 0;
388 ret
= mkdir(name
, mode
);
389 if ((ret
!= 0) && (errno
!= EEXIST
)) {
390 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", name
, mode
,
396 for (i
=0; i
<256; i
++) {
398 path
= talloc_asprintf(result
, "%s/%2.2X", name
, i
);
400 DEBUG(0, ("asprintf failed\n"));
404 ret
= mkdir(path
, mode
);
405 if ((ret
!= 0) && (errno
!= EEXIST
)) {
406 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", path
,
407 mode
, strerror(errno
)));