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/tdb_wrap/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_t fsh(const uint8_t *p
, int len
)
48 for (i
=0; i
<len
; i
++) {
49 n
= ((n
<< 5) + n
) ^ (uint32_t)(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_t *)talloc_memdup(result
, key
.dptr
,
104 if (result
->key
.dptr
== NULL
) {
105 DEBUG(0, ("talloc failed\n"));
111 file
->hash
= fsh(key
.dptr
, key
.dsize
);
112 file
->name
= hex_encode_talloc(file
, (unsigned char *)key
.dptr
, key
.dsize
);
113 if (file
->name
== NULL
) {
114 DEBUG(0, ("hex_encode failed\n"));
119 file
->path
= talloc_asprintf(file
, "%s/%2.2X/%s", ctx
->dirname
,
120 file
->hash
, file
->name
);
121 if (file
->path
== NULL
) {
122 DEBUG(0, ("talloc_asprintf failed\n"));
128 file
->fd
= open(file
->path
, O_RDWR
|O_CREAT
, 0644);
132 DEBUG(3, ("Could not open/create %s: %s\n",
133 file
->path
, strerror(errno
)));
138 talloc_set_destructor(file
, db_locked_file_destr
);
141 fl
.l_whence
= SEEK_SET
;
147 ret
= fcntl(file
->fd
, F_SETLKW
, &fl
);
148 } while ((ret
== -1) && (errno
== EINTR
));
151 DEBUG(3, ("Could not get lock on %s: %s\n",
152 file
->path
, strerror(errno
)));
157 if (sys_fstat(file
->fd
, &statbuf
, false) != 0) {
158 DEBUG(3, ("Could not fstat %s: %s\n",
159 file
->path
, strerror(errno
)));
164 if (statbuf
.st_ex_nlink
== 0) {
165 /* Someone has deleted it under the lock, retry */
170 result
->value
.dsize
= 0;
171 result
->value
.dptr
= NULL
;
173 if (statbuf
.st_ex_size
!= 0) {
176 result
->value
.dsize
= statbuf
.st_ex_size
;
177 result
->value
.dptr
= talloc_array(result
, uint8_t,
179 if (result
->value
.dptr
== NULL
) {
180 DEBUG(1, ("talloc failed\n"));
185 status
= read_data(file
->fd
, (char *)result
->value
.dptr
,
186 result
->value
.dsize
);
187 if (!NT_STATUS_IS_OK(status
)) {
188 DEBUG(3, ("read_data failed: %s\n",
195 ctx
->locked_record
= result
;
196 file
->parent
= (struct db_file_ctx
*)talloc_reference(file
, ctx
);
201 static NTSTATUS
db_file_store_root(int fd
, TDB_DATA data
)
203 if (lseek(fd
, 0, SEEK_SET
) != 0) {
204 DEBUG(0, ("lseek failed: %s\n", strerror(errno
)));
205 return map_nt_error_from_unix(errno
);
208 if (write_data(fd
, (char *)data
.dptr
, data
.dsize
) != data
.dsize
) {
209 DEBUG(3, ("write_data failed: %s\n", strerror(errno
)));
210 return map_nt_error_from_unix(errno
);
213 if (ftruncate(fd
, data
.dsize
) != 0) {
214 DEBUG(3, ("ftruncate failed: %s\n", strerror(errno
)));
215 return map_nt_error_from_unix(errno
);
221 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
223 struct db_locked_file
*file
=
224 talloc_get_type_abort(rec
->private_data
,
225 struct db_locked_file
);
229 status
= db_file_store_root(file
->fd
, data
);
235 static NTSTATUS
db_file_delete(struct db_record
*rec
)
237 struct db_locked_file
*file
=
238 talloc_get_type_abort(rec
->private_data
,
239 struct db_locked_file
);
243 res
= unlink(file
->path
);
247 DEBUG(3, ("unlink(%s) failed: %s\n", file
->path
,
249 return map_nt_error_from_unix(errno
);
255 static int db_file_traverse(struct db_context
*db
,
256 int (*fn
)(struct db_record
*rec
,
260 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
262 TALLOC_CTX
*mem_ctx
= talloc_init("traversal %s\n", ctx
->dirname
);
267 for (i
=0; i
<256; i
++) {
268 const char *dirname
= talloc_asprintf(mem_ctx
, "%s/%2.2X",
271 struct dirent
*dirent
;
273 if (dirname
== NULL
) {
274 DEBUG(0, ("talloc failed\n"));
275 TALLOC_FREE(mem_ctx
);
279 dir
= opendir(dirname
);
281 DEBUG(3, ("Could not open dir %s: %s\n", dirname
,
283 TALLOC_FREE(mem_ctx
);
287 while ((dirent
= readdir(dir
)) != NULL
) {
290 struct db_record
*rec
;
292 if ((dirent
->d_name
[0] == '.') &&
293 ((dirent
->d_name
[1] == '\0') ||
294 ((dirent
->d_name
[1] == '.') &&
295 (dirent
->d_name
[2] == '\0')))) {
299 keyblob
= strhex_to_data_blob(mem_ctx
, dirent
->d_name
);
300 if (keyblob
.data
== NULL
) {
301 DEBUG(5, ("strhex_to_data_blob failed\n"));
305 key
.dptr
= keyblob
.data
;
306 key
.dsize
= keyblob
.length
;
308 if ((ctx
->locked_record
!= NULL
) &&
309 (key
.dsize
== ctx
->locked_record
->key
.dsize
) &&
310 (memcmp(key
.dptr
, ctx
->locked_record
->key
.dptr
,
313 if (fn(ctx
->locked_record
,
314 private_data
) != 0) {
315 TALLOC_FREE(mem_ctx
);
321 rec
= db_file_fetch_locked(db
, mem_ctx
, key
);
323 /* Someone might have deleted it */
327 if (rec
->value
.dptr
== NULL
) {
334 if (fn(rec
, private_data
) != 0) {
335 TALLOC_FREE(mem_ctx
);
345 TALLOC_FREE(mem_ctx
);
349 struct db_context
*db_open_file(TALLOC_CTX
*mem_ctx
,
350 struct messaging_context
*msg_ctx
,
352 int hash_size
, int tdb_flags
,
353 int open_flags
, mode_t mode
)
355 struct db_context
*result
= NULL
;
356 struct db_file_ctx
*ctx
;
358 if (!(result
= talloc_zero(mem_ctx
, struct db_context
))) {
359 DEBUG(0, ("talloc failed\n"));
363 if (!(ctx
= talloc(result
, struct db_file_ctx
))) {
364 DEBUG(0, ("talloc failed\n"));
369 result
->private_data
= ctx
;
370 result
->fetch_locked
= db_file_fetch_locked
;
371 result
->try_fetch_locked
= NULL
;
372 result
->traverse
= db_file_traverse
;
373 result
->traverse_read
= db_file_traverse
;
374 result
->persistent
= ((tdb_flags
& TDB_CLEAR_IF_FIRST
) == 0);
376 result
->hash_size
= 0;
378 ctx
->locked_record
= NULL
;
379 if (!(ctx
->dirname
= talloc_strdup(ctx
, name
))) {
380 DEBUG(0, ("talloc failed\n"));
385 if (open_flags
& O_CREAT
) {
388 mode
|= (mode
& S_IRUSR
) ? S_IXUSR
: 0;
389 mode
|= (mode
& S_IRGRP
) ? S_IXGRP
: 0;
390 mode
|= (mode
& S_IROTH
) ? S_IXOTH
: 0;
392 ret
= mkdir(name
, mode
);
393 if ((ret
!= 0) && (errno
!= EEXIST
)) {
394 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", name
, mode
,
400 for (i
=0; i
<256; i
++) {
402 path
= talloc_asprintf(result
, "%s/%2.2X", name
, i
);
404 DEBUG(0, ("asprintf failed\n"));
408 ret
= mkdir(path
, mode
);
409 if ((ret
!= 0) && (errno
!= EEXIST
)) {
410 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", path
,
411 mode
, strerror(errno
)));