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/>.
25 /* We only support one locked record at a time -- everything else
26 * would lead to a potential deadlock anyway! */
27 struct db_record
*locked_record
;
30 struct db_locked_file
{
35 struct db_file_ctx
*parent
;
38 /* Copy from statcache.c... */
40 static uint32
fsh(const uint8
*p
, int len
)
44 for (i
=0; i
<len
; i
++) {
45 n
= ((n
<< 5) + n
) ^ (uint32
)(p
[i
]);
50 static int db_locked_file_destr(struct db_locked_file
*data
)
52 if (data
->parent
!= NULL
) {
53 data
->parent
->locked_record
= NULL
;
56 if (close(data
->fd
) != 0) {
57 DEBUG(3, ("close failed: %s\n", strerror(errno
)));
64 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
);
65 static NTSTATUS
db_file_delete(struct db_record
*rec
);
67 static struct db_record
*db_file_fetch_locked(struct db_context
*db
,
71 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
73 struct db_record
*result
;
74 struct db_locked_file
*file
;
76 SMB_STRUCT_STAT statbuf
;
80 SMB_ASSERT(ctx
->locked_record
== NULL
);
83 if (!(result
= TALLOC_P(mem_ctx
, struct db_record
))) {
84 DEBUG(0, ("talloc failed\n"));
88 if (!(file
= TALLOC_P(result
, struct db_locked_file
))) {
89 DEBUG(0, ("talloc failed\n"));
94 result
->private_data
= file
;
95 result
->store
= db_file_store
;
96 result
->delete_rec
= db_file_delete
;
98 result
->key
.dsize
= key
.dsize
;
99 result
->key
.dptr
= (uint8
*)talloc_memdup(result
, key
.dptr
, key
.dsize
);
100 if (result
->key
.dptr
== NULL
) {
101 DEBUG(0, ("talloc failed\n"));
107 file
->hash
= fsh(key
.dptr
, key
.dsize
);
108 file
->name
= hex_encode_talloc(file
, (unsigned char *)key
.dptr
, key
.dsize
);
109 if (file
->name
== NULL
) {
110 DEBUG(0, ("hex_encode failed\n"));
115 file
->path
= talloc_asprintf(file
, "%s/%2.2X/%s", ctx
->dirname
,
116 file
->hash
, file
->name
);
117 if (file
->path
== NULL
) {
118 DEBUG(0, ("talloc_asprintf failed\n"));
124 file
->fd
= open(file
->path
, O_RDWR
|O_CREAT
, 0644);
128 DEBUG(3, ("Could not open/create %s: %s\n",
129 file
->path
, strerror(errno
)));
134 talloc_set_destructor(file
, db_locked_file_destr
);
137 fl
.l_whence
= SEEK_SET
;
143 ret
= fcntl(file
->fd
, F_SETLKW
, &fl
);
144 } while ((ret
== -1) && (errno
== EINTR
));
147 DEBUG(3, ("Could not get lock on %s: %s\n",
148 file
->path
, strerror(errno
)));
153 if (sys_fstat(file
->fd
, &statbuf
) != 0) {
154 DEBUG(3, ("Could not fstat %s: %s\n",
155 file
->path
, strerror(errno
)));
160 if (statbuf
.st_nlink
== 0) {
161 /* Someone has deleted it under the lock, retry */
166 result
->value
.dsize
= 0;
167 result
->value
.dptr
= NULL
;
169 if (statbuf
.st_size
!= 0) {
170 result
->value
.dsize
= statbuf
.st_size
;
171 result
->value
.dptr
= TALLOC_ARRAY(result
, uint8
,
173 if (result
->value
.dptr
== NULL
) {
174 DEBUG(1, ("talloc failed\n"));
179 nread
= read_data(file
->fd
, (char *)result
->value
.dptr
,
180 result
->value
.dsize
);
181 if (nread
!= result
->value
.dsize
) {
182 DEBUG(3, ("read_data failed: %s\n", strerror(errno
)));
188 ctx
->locked_record
= result
;
189 file
->parent
= (struct db_file_ctx
*)talloc_reference(file
, ctx
);
194 static NTSTATUS
db_file_store_root(int fd
, TDB_DATA data
)
196 if (sys_lseek(fd
, 0, SEEK_SET
) != 0) {
197 DEBUG(0, ("sys_lseek failed: %s\n", strerror(errno
)));
198 return map_nt_error_from_unix(errno
);
201 if (write_data(fd
, (char *)data
.dptr
, data
.dsize
) != data
.dsize
) {
202 DEBUG(3, ("write_data failed: %s\n", strerror(errno
)));
203 return map_nt_error_from_unix(errno
);
206 if (sys_ftruncate(fd
, data
.dsize
) != 0) {
207 DEBUG(3, ("sys_ftruncate failed: %s\n", strerror(errno
)));
208 return map_nt_error_from_unix(errno
);
214 static NTSTATUS
db_file_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
216 struct db_locked_file
*file
=
217 talloc_get_type_abort(rec
->private_data
,
218 struct db_locked_file
);
222 status
= db_file_store_root(file
->fd
, data
);
228 static NTSTATUS
db_file_delete(struct db_record
*rec
)
230 struct db_locked_file
*file
=
231 talloc_get_type_abort(rec
->private_data
,
232 struct db_locked_file
);
236 res
= unlink(file
->path
);
240 DEBUG(3, ("unlink(%s) failed: %s\n", file
->path
,
242 return map_nt_error_from_unix(errno
);
248 static int db_file_traverse(struct db_context
*db
,
249 int (*fn
)(struct db_record
*rec
,
253 struct db_file_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
255 TALLOC_CTX
*mem_ctx
= talloc_init("traversal %s\n", ctx
->dirname
);
260 for (i
=0; i
<256; i
++) {
261 const char *dirname
= talloc_asprintf(mem_ctx
, "%s/%2.2X",
264 struct dirent
*dirent
;
266 if (dirname
== NULL
) {
267 DEBUG(0, ("talloc failed\n"));
268 TALLOC_FREE(mem_ctx
);
272 dir
= opendir(dirname
);
274 DEBUG(3, ("Could not open dir %s: %s\n", dirname
,
276 TALLOC_FREE(mem_ctx
);
280 while ((dirent
= readdir(dir
)) != NULL
) {
283 struct db_record
*rec
;
285 if ((dirent
->d_name
[0] == '.') &&
286 ((dirent
->d_name
[1] == '\0') ||
287 ((dirent
->d_name
[1] == '.') &&
288 (dirent
->d_name
[2] == '\0')))) {
292 keyblob
= strhex_to_data_blob(mem_ctx
, dirent
->d_name
);
293 if (keyblob
.data
== NULL
) {
294 DEBUG(5, ("strhex_to_data_blob failed\n"));
298 key
.dptr
= keyblob
.data
;
299 key
.dsize
= keyblob
.length
;
301 if ((ctx
->locked_record
!= NULL
) &&
302 (key
.dsize
== ctx
->locked_record
->key
.dsize
) &&
303 (memcmp(key
.dptr
, ctx
->locked_record
->key
.dptr
,
306 if (fn(ctx
->locked_record
,
307 private_data
) != 0) {
308 TALLOC_FREE(mem_ctx
);
314 rec
= db_file_fetch_locked(db
, mem_ctx
, key
);
316 /* Someone might have deleted it */
320 if (rec
->value
.dptr
== NULL
) {
327 if (fn(rec
, private_data
) != 0) {
328 TALLOC_FREE(mem_ctx
);
338 TALLOC_FREE(mem_ctx
);
342 struct db_context
*db_open_file(TALLOC_CTX
*mem_ctx
,
343 struct messaging_context
*msg_ctx
,
345 int hash_size
, int tdb_flags
,
346 int open_flags
, mode_t mode
)
348 struct db_context
*result
= NULL
;
349 struct db_file_ctx
*ctx
;
351 if (!(result
= TALLOC_ZERO_P(mem_ctx
, struct db_context
))) {
352 DEBUG(0, ("talloc failed\n"));
356 if (!(ctx
= TALLOC_P(result
, struct db_file_ctx
))) {
357 DEBUG(0, ("talloc failed\n"));
362 result
->private_data
= ctx
;
363 result
->fetch_locked
= db_file_fetch_locked
;
364 result
->traverse
= db_file_traverse
;
365 result
->traverse_read
= db_file_traverse
;
366 result
->persistent
= ((tdb_flags
& TDB_CLEAR_IF_FIRST
) == 0);
368 ctx
->locked_record
= NULL
;
369 if (!(ctx
->dirname
= talloc_strdup(ctx
, name
))) {
370 DEBUG(0, ("talloc failed\n"));
375 if (open_flags
& O_CREAT
) {
378 mode
|= (mode
& S_IRUSR
) ? S_IXUSR
: 0;
379 mode
|= (mode
& S_IRGRP
) ? S_IXGRP
: 0;
380 mode
|= (mode
& S_IROTH
) ? S_IXOTH
: 0;
382 ret
= mkdir(name
, mode
);
383 if ((ret
!= 0) && (errno
!= EEXIST
)) {
384 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", name
, mode
,
390 for (i
=0; i
<256; i
++) {
392 path
= talloc_asprintf(result
, "%s/%2.2X", name
, i
);
394 DEBUG(0, ("asprintf failed\n"));
398 ret
= mkdir(path
, mode
);
399 if ((ret
!= 0) && (errno
!= EEXIST
)) {
400 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", path
,
401 mode
, strerror(errno
)));