2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)log_archive.c 10.37 (Sleepycat) 5/3/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
24 #include "db_dispatch.h"
27 #include "common_ext.h"
28 #include "clib_ext.h" /* XXX: needed for getcwd. */
30 static int __absname
__P((char *, char *, char **));
31 static int __build_data
__P((DB_LOG
*, char *, char ***, void *(*)(size_t)));
32 static int __cmpfunc
__P((const void *, const void *));
33 static int __usermem
__P((char ***, void *(*)(size_t)));
37 * Supporting function for db_archive(1).
40 log_archive(dblp
, listp
, flags
, db_malloc
)
44 void *(*db_malloc
) __P((size_t));
49 int array_size
, n
, ret
;
50 char **array
, **arrayp
, *name
, *p
, *pref
, buf
[MAXPATHLEN
];
54 #define OKFLAGS (DB_ARCH_ABS | DB_ARCH_DATA | DB_ARCH_LOG)
57 __db_fchk(dblp
->dbenv
, "log_archive", flags
, OKFLAGS
)) != 0)
60 __db_fcchk(dblp
->dbenv
,
61 "log_archive", flags
, DB_ARCH_DATA
, DB_ARCH_LOG
)) != 0)
66 * Get the absolute pathname of the current directory. It would
67 * be nice to get the shortest pathname of the database directory,
68 * but that's just not possible.
70 if (LF_ISSET(DB_ARCH_ABS
)) {
72 if ((pref
= getcwd(buf
, sizeof(buf
))) == NULL
)
73 return (errno
== 0 ? ENOMEM
: errno
);
77 switch (LF_ISSET(~DB_ARCH_ABS
)) {
79 return (__build_data(dblp
, pref
, listp
, db_malloc
));
81 memset(&rec
, 0, sizeof(rec
));
82 if (F_ISSET(dblp
, DB_AM_THREAD
))
83 F_SET(&rec
, DB_DBT_MALLOC
);
84 if ((ret
= log_get(dblp
, &stable_lsn
, &rec
, DB_LAST
)) != 0)
86 if (F_ISSET(dblp
, DB_AM_THREAD
))
88 fnum
= stable_lsn
.file
;
91 if ((ret
= __log_findckp(dblp
, &stable_lsn
)) != 0) {
93 * A return of DB_NOTFOUND means that we didn't find
94 * any records in the log (so we are not going to be
95 * deleting any log files).
97 if (ret
!= DB_NOTFOUND
)
102 /* Remove any log files before the last stable LSN. */
103 fnum
= stable_lsn
.file
- 1;
107 #define LIST_INCREMENT 64
108 /* Get some initial space. */
110 (char **)__db_malloc(sizeof(char *) * (array_size
= 10))) == NULL
)
114 /* Build an array of the file names. */
115 for (n
= 0; fnum
> 0; --fnum
) {
116 if ((ret
= __log_name(dblp
, fnum
, &name
)) != 0)
118 if (__db_exists(name
, NULL
) != 0)
121 if (n
>= array_size
- 1) {
122 array_size
+= LIST_INCREMENT
;
123 if ((array
= (char **)__db_realloc(array
,
124 sizeof(char *) * array_size
)) == NULL
) {
130 if (LF_ISSET(DB_ARCH_ABS
)) {
131 if ((ret
= __absname(pref
, name
, &array
[n
])) != 0)
134 } else if ((p
= __db_rpath(name
)) != NULL
) {
135 if ((array
[n
] = (char *)__db_strdup(p
+ 1)) == NULL
) {
146 /* If there's nothing to return, we're done. */
154 qsort(array
, (size_t)n
, sizeof(char *), __cmpfunc
);
156 /* Rework the memory. */
157 if ((ret
= __usermem(&array
, db_malloc
)) != 0)
163 err
: if (array
!= NULL
) {
164 for (arrayp
= array
; *arrayp
!= NULL
; ++arrayp
)
173 * Build a list of datafiles for return.
176 __build_data(dblp
, pref
, listp
, db_malloc
)
178 char *pref
, ***listp
;
179 void *(*db_malloc
) __P((size_t));
183 __log_register_args
*argp
;
185 int array_size
, last
, n
, nxt
, ret
;
186 char **array
, **arrayp
, *p
, *real_name
;
188 /* Get some initial space. */
190 (char **)__db_malloc(sizeof(char *) * (array_size
= 10))) == NULL
)
194 memset(&rec
, 0, sizeof(rec
));
195 if (F_ISSET(dblp
, DB_AM_THREAD
))
196 F_SET(&rec
, DB_DBT_MALLOC
);
197 for (n
= 0, ret
= log_get(dblp
, &lsn
, &rec
, DB_FIRST
);
198 ret
== 0; ret
= log_get(dblp
, &lsn
, &rec
, DB_NEXT
)) {
199 if (rec
.size
< sizeof(rectype
)) {
201 __db_err(dblp
->dbenv
, "log_archive: bad log record");
205 memcpy(&rectype
, rec
.data
, sizeof(rectype
));
206 if (rectype
!= DB_log_register
) {
207 if (F_ISSET(dblp
, DB_AM_THREAD
)) {
213 if ((ret
= __log_register_read(rec
.data
, &argp
)) != 0) {
215 __db_err(dblp
->dbenv
,
216 "log_archive: unable to read log record");
220 if (n
>= array_size
- 1) {
221 array_size
+= LIST_INCREMENT
;
222 if ((array
= (char **)__db_realloc(array
,
223 sizeof(char *) * array_size
)) == NULL
) {
229 if ((array
[n
] = (char *)__db_strdup(argp
->name
.data
)) == NULL
) {
231 lg_free
: if (F_ISSET(&rec
, DB_DBT_MALLOC
) && rec
.data
!= NULL
)
239 if (F_ISSET(dblp
, DB_AM_THREAD
)) {
245 /* If there's nothing to return, we're done. */
253 qsort(array
, (size_t)n
, sizeof(char *), __cmpfunc
);
256 * Build the real pathnames, discarding nonexistent files and
259 for (last
= nxt
= 0; nxt
< n
;) {
261 * Discard duplicates. Last is the next slot we're going
262 * to return to the user, nxt is the next slot that we're
266 array
[last
] = array
[nxt
];
269 for (++nxt
; nxt
< n
&&
270 strcmp(array
[last
], array
[nxt
]) == 0; ++nxt
) {
275 /* Get the real name. */
276 if ((ret
= __db_appname(dblp
->dbenv
,
277 DB_APP_DATA
, NULL
, array
[last
], 0, NULL
, &real_name
)) != 0)
280 /* If the file doesn't exist, ignore it. */
281 if (__db_exists(real_name
, NULL
) != 0) {
288 /* Rework the name as requested by the user. */
292 ret
= __absname(pref
, real_name
, &array
[last
]);
296 } else if ((p
= __db_rpath(real_name
)) != NULL
) {
297 array
[last
] = (char *)__db_strdup(p
+ 1);
299 if (array
[last
] == NULL
)
302 array
[last
] = real_name
;
306 /* NULL-terminate the list. */
309 /* Rework the memory. */
310 if ((ret
= __usermem(&array
, db_malloc
)) != 0)
318 * We've possibly inserted NULLs into the array list, so clean up a
319 * bit so that the other error processing works.
322 for (; nxt
< n
; ++nxt
)
326 err1
: if (array
!= NULL
) {
327 for (arrayp
= array
; *arrayp
!= NULL
; ++arrayp
)
336 * Return an absolute path name for the file.
339 __absname(pref
, name
, newnamep
)
340 char *pref
, *name
, **newnamep
;
342 size_t l_pref
, l_name
;
346 l_name
= strlen(name
);
347 isabspath
= __db_abspath(name
);
348 l_pref
= isabspath
? 0 : strlen(pref
);
350 /* Malloc space for concatenating the two. */
352 newname
= (char *)__db_malloc(l_pref
+ l_name
+ 2)) == NULL
)
355 /* Build the name. If `name' is an absolute path, ignore any prefix. */
357 memcpy(newname
, pref
, l_pref
);
358 if (strchr(PATH_SEPARATOR
, newname
[l_pref
- 1]) == NULL
)
359 newname
[l_pref
++] = PATH_SEPARATOR
[0];
361 memcpy(newname
+ l_pref
, name
, l_name
+ 1);
368 * Create a single chunk of memory that holds the returned information.
369 * If the user has their own malloc routine, use it.
372 __usermem(listp
, cmpfunc
)
374 void *(*cmpfunc
) __P((size_t));
377 char **array
, **arrayp
, **orig
, *strp
;
379 /* Find out how much space we need. */
380 for (len
= 0, orig
= *listp
; *orig
!= NULL
; ++orig
)
381 len
+= sizeof(char *) + strlen(*orig
) + 1;
382 len
+= sizeof(char *);
385 * Allocate it and set up the pointers.
388 * Don't simplify this expression, SunOS compilers don't like it.
391 array
= (char **)__db_malloc(len
);
393 array
= (char **)cmpfunc(len
);
396 strp
= (char *)(array
+ (orig
- *listp
) + 1);
398 /* Copy the original information into the new memory. */
399 for (orig
= *listp
, arrayp
= array
; *orig
!= NULL
; ++orig
, ++arrayp
) {
401 memcpy(strp
, *orig
, len
+ 1);
408 /* NULL-terminate the list. */
421 return (strcmp(*((char * const *)p1
), *((char * const *)p2
)));