2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Rafal Szczesniak 2002
6 Copyright (C) Michael Adam 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
32 static struct flock flock_struct
;
34 /* Return a value which is none of v1, v2 or v3. */
35 static inline short int invalid_value(short int v1
, short int v2
, short int v3
)
37 short int try = (v1
+v2
+v3
)^((v1
+v2
+v3
) << 16);
38 while (try == v1
|| try == v2
|| try == v3
)
43 /* We invalidate in as many ways as we can, so the OS rejects it */
44 static void invalidate_flock_struct(int signum
)
46 flock_struct
.l_type
= invalid_value(F_RDLCK
, F_WRLCK
, F_UNLCK
);
47 flock_struct
.l_whence
= invalid_value(SEEK_SET
, SEEK_CUR
, SEEK_END
);
48 flock_struct
.l_start
= -1;
49 /* A large negative. */
50 flock_struct
.l_len
= (((off_t
)1 << (sizeof(off_t
)*CHAR_BIT
- 1)) + 1);
53 static int timeout_lock(int fd
, int rw
, off_t off
, off_t len
, bool waitflag
,
57 unsigned int timeout
= *(unsigned int *)_timeout
;
59 flock_struct
.l_type
= rw
;
60 flock_struct
.l_whence
= SEEK_SET
;
61 flock_struct
.l_start
= off
;
62 flock_struct
.l_len
= len
;
64 CatchSignal(SIGALRM
, invalidate_flock_struct
);
69 ret
= fcntl(fd
, F_SETLKW
, &flock_struct
);
71 ret
= fcntl(fd
, F_SETLK
, &flock_struct
);
76 /* Not signalled? Something else went wrong. */
77 if (flock_struct
.l_len
== len
) {
78 if (errno
== EAGAIN
|| errno
== EINTR
)
93 static int tdb_chainlock_with_timeout_internal(struct tdb_context
*tdb
,
98 union tdb_attribute locking
;
102 locking
.base
.attr
= TDB_ATTRIBUTE_FLOCK
;
103 ecode
= tdb_get_attribute(tdb
, &locking
);
104 if (ecode
!= TDB_SUCCESS
)
107 /* Replace locking function with our own. */
108 locking
.flock
.data
= &timeout
;
109 locking
.flock
.lock
= timeout_lock
;
111 ecode
= tdb_set_attribute(tdb
, &locking
);
112 if (ecode
!= TDB_SUCCESS
)
115 if (rw_type
== F_RDLCK
)
116 ecode
= tdb_chainlock_read(tdb
, key
);
118 ecode
= tdb_chainlock(tdb
, key
);
121 tdb_unset_attribute(tdb
, TDB_ATTRIBUTE_FLOCK
);
123 return ecode
== TDB_SUCCESS
? 0 : -1;
126 /* these are little tdb utility functions that are meant to make
127 dealing with a tdb database a little less cumbersome in Samba */
129 static SIG_ATOMIC_T gotalarm
;
131 /***************************************************************
132 Signal function to tell us we timed out.
133 ****************************************************************/
135 static void gotalarm_sig(int signum
)
140 /****************************************************************************
141 Lock a chain with timeout (in seconds).
142 ****************************************************************************/
144 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT
*tdb
, TDB_DATA key
, unsigned int timeout
, int rw_type
)
146 /* Allow tdb_chainlock to be interrupted by an alarm. */
151 CatchSignal(SIGALRM
, gotalarm_sig
);
152 tdb_setalarm_sigptr(tdb
, &gotalarm
);
156 if (rw_type
== F_RDLCK
)
157 ret
= tdb_chainlock_read(tdb
, key
);
159 ret
= tdb_chainlock(tdb
, key
);
163 tdb_setalarm_sigptr(tdb
, NULL
);
164 CatchSignal(SIGALRM
, SIG_IGN
);
165 if (gotalarm
&& (ret
!= 0)) {
166 DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
167 timeout
, key
.dptr
, tdb_name(tdb
)));
168 /* TODO: If we time out waiting for a lock, it might
169 * be nice to use F_GETLK to get the pid of the
170 * process currently holding the lock and print that
171 * as part of the debugging message. -- mbp */
176 return ret
== 0 ? 0 : -1;
180 /****************************************************************************
181 Write lock a chain. Return non-zero if timeout or lock failed.
182 ****************************************************************************/
184 int tdb_chainlock_with_timeout( TDB_CONTEXT
*tdb
, TDB_DATA key
, unsigned int timeout
)
186 return tdb_chainlock_with_timeout_internal(tdb
, key
, timeout
, F_WRLCK
);
189 int tdb_lock_bystring_with_timeout(TDB_CONTEXT
*tdb
, const char *keyval
,
192 TDB_DATA key
= string_term_tdb_data(keyval
);
194 return tdb_chainlock_with_timeout(tdb
, key
, timeout
);
197 /****************************************************************************
198 Read lock a chain by string. Return non-zero if timeout or lock failed.
199 ****************************************************************************/
201 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT
*tdb
, const char *keyval
, unsigned int timeout
)
203 TDB_DATA key
= string_term_tdb_data(keyval
);
205 return tdb_chainlock_with_timeout_internal(tdb
, key
, timeout
, F_RDLCK
);
211 int tdb_trans_store_bystring(TDB_CONTEXT
*tdb
, const char *keystr
,
212 TDB_DATA data
, int flags
)
214 TDB_DATA key
= string_term_tdb_data(keystr
);
216 return tdb_trans_store(tdb
, key
, data
, flags
);
219 /****************************************************************************
220 Useful pair of routines for packing/unpacking data consisting of
221 integers and strings.
222 ****************************************************************************/
224 static size_t tdb_pack_va(uint8
*buf
, int bufsize
, const char *fmt
, va_list ap
)
235 const char *fmt0
= fmt
;
236 int bufsize0
= bufsize
;
239 switch ((c
= *fmt
++)) {
240 case 'b': /* unsigned 8-bit integer */
242 bt
= (uint8
)va_arg(ap
, int);
243 if (bufsize
&& bufsize
>= len
)
246 case 'w': /* unsigned 16-bit integer */
248 w
= (uint16
)va_arg(ap
, int);
249 if (bufsize
&& bufsize
>= len
)
252 case 'd': /* signed 32-bit integer (standard int in most systems) */
254 d
= va_arg(ap
, uint32
);
255 if (bufsize
&& bufsize
>= len
)
258 case 'p': /* pointer */
260 p
= va_arg(ap
, void *);
262 if (bufsize
&& bufsize
>= len
)
265 case 'P': /* null-terminated string */
266 s
= va_arg(ap
,char *);
269 if (bufsize
&& bufsize
>= len
)
272 case 'f': /* null-terminated string */
273 s
= va_arg(ap
,char *);
276 if (bufsize
&& bufsize
>= len
)
279 case 'B': /* fixed-length string */
281 s
= va_arg(ap
, char *);
283 if (bufsize
&& bufsize
>= len
) {
289 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
302 DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n",
303 fmt0
, bufsize0
, (int)PTR_DIFF(buf
, buf0
)));
305 return PTR_DIFF(buf
, buf0
);
308 size_t tdb_pack(uint8
*buf
, int bufsize
, const char *fmt
, ...)
314 result
= tdb_pack_va(buf
, bufsize
, fmt
, ap
);
319 bool tdb_pack_append(TALLOC_CTX
*mem_ctx
, uint8
**buf
, size_t *len
,
320 const char *fmt
, ...)
326 len1
= tdb_pack_va(NULL
, 0, fmt
, ap
);
329 if (mem_ctx
!= NULL
) {
330 *buf
= talloc_realloc(mem_ctx
, *buf
, uint8
,
333 *buf
= SMB_REALLOC_ARRAY(*buf
, uint8
, (*len
) + len1
);
341 len2
= tdb_pack_va((*buf
)+(*len
), len1
, fmt
, ap
);
353 /****************************************************************************
354 Useful pair of routines for packing/unpacking data consisting of
355 integers and strings.
356 ****************************************************************************/
358 int tdb_unpack(const uint8
*buf
, int bufsize
, const char *fmt
, ...)
369 const uint8
*buf0
= buf
;
370 const char *fmt0
= fmt
;
371 int bufsize0
= bufsize
;
376 switch ((c
=*fmt
++)) {
377 case 'b': /* unsigned 8-bit integer */
379 bt
= va_arg(ap
, uint8
*);
384 case 'w': /* unsigned 16-bit integer */
386 w
= va_arg(ap
, uint16
*);
391 case 'd': /* unsigned 32-bit integer (standard int in most systems) */
393 d
= va_arg(ap
, uint32
*);
398 case 'p': /* pointer */
400 p
= va_arg(ap
, void **);
404 * This isn't a real pointer - only a token (1 or 0)
405 * to mark the fact a pointer is present.
408 *p
= (void *)(IVAL(buf
, 0) ? (void *)1 : NULL
);
410 case 'P': /* null-terminated string */
411 /* Return malloc'ed string. */
412 ps
= va_arg(ap
,char **);
413 len
= strnlen((const char *)buf
, bufsize
) + 1;
416 *ps
= SMB_STRDUP((const char *)buf
);
418 case 'f': /* null-terminated string */
419 s
= va_arg(ap
,char *);
420 len
= strnlen((const char *)buf
, bufsize
) + 1;
421 if (bufsize
< len
|| len
> sizeof(fstring
))
425 case 'B': /* fixed-length string */
426 i
= va_arg(ap
, int *);
427 b
= va_arg(ap
, char **);
439 *b
= (char *)SMB_MALLOC(*i
);
442 memcpy(*b
, buf
+4, *i
);
445 DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
458 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
459 fmt0
, bufsize0
, (int)PTR_DIFF(buf
, buf0
)));
461 return PTR_DIFF(buf
, buf0
);
469 /****************************************************************************
470 Log tdb messages via DEBUG().
471 ****************************************************************************/
474 static void tdb_log(TDB_CONTEXT
*tdb
, enum tdb_log_level level
,
475 enum TDB_ERROR ecode
, const char *message
, void *unused
)
477 DEBUG((int)level
, ("tdb(%s):%s: %s",
478 tdb_name(tdb
) ? tdb_name(tdb
) : "unnamed",
479 tdb_errorstr(ecode
), message
));
482 static void tdb_log(TDB_CONTEXT
*tdb
, enum tdb_debug_level level
, const char *format
, ...)
488 va_start(ap
, format
);
489 ret
= vasprintf(&ptr
, format
, ap
);
492 if ((ret
== -1) || !*ptr
)
495 DEBUG((int)level
, ("tdb(%s): %s", tdb_name(tdb
) ? tdb_name(tdb
) : "unnamed", ptr
));
500 /****************************************************************************
501 Like tdb_open() but also setup a logging function that redirects to
502 the samba DEBUG() system.
503 ****************************************************************************/
505 TDB_CONTEXT
*tdb_open_log(const char *name
, int hash_size
, int tdb_flags
,
506 int open_flags
, mode_t mode
)
511 tdb_flags
|= TDB_NOMMAP
;
513 if ((hash_size
== 0) && (name
!= NULL
)) {
514 const char *base
= strrchr_m(name
, '/');
521 hash_size
= lp_parm_int(-1, "tdb_hashsize", base
, 0);
524 tdb
= tdb_open_compat(name
, hash_size
, tdb_flags
,
525 open_flags
, mode
, tdb_log
, NULL
);
532 /****************************************************************************
533 tdb_store, wrapped in a transaction. This way we make sure that a process
534 that dies within writing does not leave a corrupt tdb behind.
535 ****************************************************************************/
537 int tdb_trans_store(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA dbuf
,
542 if ((res
= tdb_transaction_start(tdb
)) != 0) {
543 DEBUG(5, ("tdb_transaction_start failed\n"));
547 if ((res
= tdb_store(tdb
, key
, dbuf
, flag
)) != 0) {
548 DEBUG(10, ("tdb_store failed\n"));
549 tdb_transaction_cancel(tdb
);
553 if ((res
= tdb_transaction_commit(tdb
)) != 0) {
554 DEBUG(5, ("tdb_transaction_commit failed\n"));
560 /****************************************************************************
561 tdb_delete, wrapped in a transaction. This way we make sure that a process
562 that dies within deleting does not leave a corrupt tdb behind.
563 ****************************************************************************/
565 int tdb_trans_delete(struct tdb_context
*tdb
, TDB_DATA key
)
569 if ((res
= tdb_transaction_start(tdb
)) != 0) {
570 DEBUG(5, ("tdb_transaction_start failed\n"));
574 if ((res
= tdb_delete(tdb
, key
)) != 0) {
575 DEBUG(10, ("tdb_delete failed\n"));
576 tdb_transaction_cancel(tdb
);
580 if ((res
= tdb_transaction_commit(tdb
)) != 0) {
581 DEBUG(5, ("tdb_transaction_commit failed\n"));
587 NTSTATUS
map_nt_error_from_tdb(enum TDB_ERROR err
)
589 NTSTATUS result
= NT_STATUS_INTERNAL_ERROR
;
593 result
= NT_STATUS_OK
;
595 case TDB_ERR_CORRUPT
:
596 result
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
599 result
= NT_STATUS_UNEXPECTED_IO_ERROR
;
602 result
= NT_STATUS_NO_MEMORY
;
605 result
= NT_STATUS_OBJECT_NAME_COLLISION
;
610 * TDB_ERR_LOCK is very broad, we could for example
611 * distinguish between fcntl locks and invalid lock
612 * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
615 result
= NT_STATUS_FILE_LOCK_CONFLICT
;
620 case TDB_ERR_LOCK_TIMEOUT
:
622 * These two ones in the enum are not actually used
624 result
= NT_STATUS_FILE_LOCK_CONFLICT
;
627 case TDB_ERR_NOEXIST
:
628 result
= NT_STATUS_NOT_FOUND
;
631 result
= NT_STATUS_INVALID_PARAMETER
;
634 result
= NT_STATUS_ACCESS_DENIED
;
637 case TDB_ERR_NESTING
:
638 result
= NT_STATUS_INTERNAL_ERROR
;
645 int tdb_data_cmp(TDB_DATA t1
, TDB_DATA t2
)
648 if (t1
.dptr
== NULL
&& t2
.dptr
!= NULL
) {
651 if (t1
.dptr
!= NULL
&& t2
.dptr
== NULL
) {
654 if (t1
.dptr
== t2
.dptr
) {
655 return t1
.dsize
- t2
.dsize
;
657 ret
= memcmp(t1
.dptr
, t2
.dptr
, MIN(t1
.dsize
, t2
.dsize
));
659 return t1
.dsize
- t2
.dsize
;