2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #include <afs/afsutil.h>
20 #define UBIK_INTERNALS 1
24 * These routines are called via the proc ptr in the ubik_dbase structure. They provide access to
25 * the physical disk, by converting the file numbers being processed ( >= 0 for user data space, < 0
26 * for ubik system files, such as the log) to actual pathnames to open, read, write, truncate, sync,
31 static struct fdcache
{
35 } fdcache
[MAXFDCACHE
];
37 /* Cache a stdio handle for a given database file, for uphys_buf_append
38 * operations. We only use buf_append for one file at a time, so only try to
39 * cache a single file handle, since that's all we should need. */
40 static struct buf_fdcache
{
45 static char pbuffer
[1024];
47 static int uphys_buf_flush(struct ubik_dbase
*adbase
, afs_int32 afid
);
50 * \warning Beware, when using this function, of the header in front of most files.
53 uphys_open(struct ubik_dbase
*adbase
, afs_int32 afid
)
59 struct fdcache
*bestfd
;
61 /* initialize package */
65 for (i
= 0; i
< MAXFDCACHE
; tfd
++, i
++) {
66 tfd
->fd
= -1; /* invalid value */
67 tfd
->fileID
= -10000; /* invalid value */
72 /* scan file descr cache */
73 for (tfd
= fdcache
, i
= 0; i
< MAXFDCACHE
; i
++, tfd
++) {
74 if (afid
== tfd
->fileID
&& tfd
->refCount
== 0) { /* don't use open fd */
75 lseek(tfd
->fd
, 0, 0); /* reset ptr just like open would have */
81 /* not found, open it and try to enter in cache */
82 snprintf(pbuffer
, sizeof(pbuffer
), "%s.DB%s%d", adbase
->pathName
,
83 (afid
<0)?"SYS":"", (afid
<0)?-afid
:afid
);
84 fd
= open(pbuffer
, O_CREAT
| O_RDWR
, 0600);
86 /* try opening read-only */
87 fd
= open(pbuffer
, O_RDONLY
, 0);
92 /* enter it in the cache */
95 for (i
= 0; i
< MAXFDCACHE
; i
++, tfd
++) { /* look for empty slot */
101 if (!bestfd
) { /* look for reclaimable slot */
103 for (i
= 0; i
< MAXFDCACHE
; i
++, tfd
++) {
104 if (tfd
->refCount
== 0) {
110 if (bestfd
) { /* found a usable slot */
115 tfd
->refCount
= 1; /* us */
119 /* finally, we're done */
124 * \brief Close the file, maintaining ref count in cache structure.
135 for (i
= 0; i
< MAXFDCACHE
; i
++, tfd
++) {
136 if (tfd
->fd
== afd
) {
137 if (tfd
->fileID
!= -10000) {
141 if (tfd
->refCount
> 0) {
143 if (tfd
->refCount
== 0) {
158 uphys_stat(struct ubik_dbase
*adbase
, afs_int32 afid
, struct ubik_stat
*astat
)
164 fd
= uphys_open(adbase
, afid
);
167 code
= fstat(fd
, &tstat
);
172 code
= tstat
.st_size
- HDRSIZE
;
181 uphys_read(struct ubik_dbase
*adbase
, afs_int32 afile
,
182 void *abuffer
, afs_int32 apos
, afs_int32 alength
)
187 fd
= uphys_open(adbase
, afile
);
190 code
= lseek(fd
, apos
+ HDRSIZE
, 0);
195 code
= read(fd
, abuffer
, alength
);
201 uphys_write(struct ubik_dbase
*adbase
, afs_int32 afile
,
202 void *abuffer
, afs_int32 apos
, afs_int32 alength
)
208 fd
= uphys_open(adbase
, afile
);
211 code
= lseek(fd
, apos
+ HDRSIZE
, 0);
216 length
= write(fd
, abuffer
, alength
);
217 code
= uphys_close(fd
);
225 uphys_truncate(struct ubik_dbase
*adbase
, afs_int32 afile
,
230 /* Just in case there's memory-buffered data for this file, flush it before
232 if (uphys_buf_flush(adbase
, afile
) < 0) {
236 fd
= uphys_open(adbase
, afile
);
239 code
= ftruncate(fd
, asize
+ HDRSIZE
);
245 * \brief Get number of dbase files.
247 * \todo Really should scan dir for data.
250 uphys_getnfiles(struct ubik_dbase
*adbase
)
252 /* really should scan dir for data */
257 * \brief Get database label, with \p aversion in host order.
260 uphys_getlabel(struct ubik_dbase
*adbase
, afs_int32 afile
,
261 struct ubik_version
*aversion
)
263 struct ubik_hdr thdr
;
266 fd
= uphys_open(adbase
, afile
);
269 code
= read(fd
, &thdr
, sizeof(thdr
));
270 if (code
!= sizeof(thdr
)) {
274 aversion
->epoch
= ntohl(thdr
.version
.epoch
);
275 aversion
->counter
= ntohl(thdr
.version
.counter
);
281 * \brief Label database, with \p aversion in host order.
284 uphys_setlabel(struct ubik_dbase
*adbase
, afs_int32 afile
,
285 struct ubik_version
*aversion
)
287 struct ubik_hdr thdr
;
290 fd
= uphys_open(adbase
, afile
);
294 memset(&thdr
, 0, sizeof(thdr
));
296 thdr
.version
.epoch
= htonl(aversion
->epoch
);
297 thdr
.version
.counter
= htonl(aversion
->counter
);
298 thdr
.magic
= htonl(UBIK_MAGIC
);
299 thdr
.size
= htons(HDRSIZE
);
300 code
= write(fd
, &thdr
, sizeof(thdr
));
301 fsync(fd
); /* preserve over crash */
303 if (code
!= sizeof(thdr
)) {
310 uphys_sync(struct ubik_dbase
*adbase
, afs_int32 afile
)
314 /* Flush any in-memory data, so we can sync it. */
315 if (uphys_buf_flush(adbase
, afile
) < 0) {
319 fd
= uphys_open(adbase
, afile
);
326 uphys_invalidate(struct ubik_dbase
*adbase
, afs_int32 afid
)
331 /* scan file descr cache */
332 for (tfd
= fdcache
, i
= 0; i
< MAXFDCACHE
; i
++, tfd
++) {
333 if (afid
== tfd
->fileID
) {
334 tfd
->fileID
= -10000;
335 if (tfd
->fd
>= 0 && tfd
->refCount
== 0) {
345 uphys_buf_append_open(struct ubik_dbase
*adbase
, afs_int32 afid
)
347 /* If we have a cached handle open for this file, just return it. */
348 if (buf_fdcache
.stream
&& buf_fdcache
.fileID
== afid
) {
349 return buf_fdcache
.stream
;
352 /* Otherwise, close the existing handle, and open a new handle for the
355 if (buf_fdcache
.stream
) {
356 fclose(buf_fdcache
.stream
);
359 snprintf(pbuffer
, sizeof(pbuffer
), "%s.DB%s%d", adbase
->pathName
,
360 (afid
<0)?"SYS":"", (afid
<0)?-afid
:afid
);
361 buf_fdcache
.stream
= fopen(pbuffer
, "a");
362 buf_fdcache
.fileID
= afid
;
363 return buf_fdcache
.stream
;
367 uphys_buf_flush(struct ubik_dbase
*adbase
, afs_int32 afid
)
369 if (buf_fdcache
.stream
&& buf_fdcache
.fileID
== afid
) {
370 int code
= fflush(buf_fdcache
.stream
);
378 /* Append the given data to the given database file, allowing the data to be
379 * buffered in memory. */
381 uphys_buf_append(struct ubik_dbase
*adbase
, afs_int32 afid
, void *adata
,
387 stream
= uphys_buf_append_open(adbase
, afid
);
392 code
= fwrite(adata
, alength
, 1, stream
);