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>
16 #include <afs/bubasics.h>
17 #include <afs/audit.h>
18 #include <afs/afsutil.h>
20 #include "budb_errs.h"
22 #include "error_macros.h"
23 #include "budb_internal.h"
25 /* --------------------------------
26 * interface & support code to manage text blocks within the
28 * --------------------------------
33 * routine mallocs storage for charListPtr, freed by stub
36 afs_int32
GetText(struct rx_call
*, afs_uint32
, afs_int32
, afs_int32
,
37 afs_int32
, afs_int32
*, charListT
*);
38 afs_int32
GetTextVersion(struct rx_call
*, afs_int32
, afs_uint32
*);
39 afs_int32
SaveText(struct rx_call
*, afs_uint32
, afs_int32
, afs_int32
,
40 afs_int32
, charListT
*);
43 SBUDB_GetText(struct rx_call
*call
, afs_uint32 lockHandle
, afs_int32 textType
,
44 afs_int32 maxLength
, afs_int32 offset
, afs_int32
*nextOffset
,
45 charListT
*charListPtr
)
50 GetText(call
, lockHandle
, textType
, maxLength
, offset
, nextOffset
,
52 osi_auditU(call
, BUDB_GetTxtEvent
, code
, AUD_LONG
, textType
, AUD_END
);
57 GetText(struct rx_call
*call
, afs_uint32 lockHandle
, afs_int32 textType
,
58 afs_int32 maxLength
, afs_int32 offset
, afs_int32
*nextOffset
,
59 charListT
*charListPtr
)
61 struct ubik_trans
*ut
= 0;
63 afs_int32 transferSize
, chunkSize
;
64 afs_int32 blockOffset
;
67 struct textBlock
*tbPtr
;
68 afs_int32 textRemaining
;
72 LogDebug(5, "GetText: type %d, offset %d, nextOffset %"AFS_PTR_FMT
73 ", maxLength %d\n", textType
, offset
, nextOffset
, maxLength
);
75 if (callPermitted(call
) == 0) {
76 code
= BUDB_NOTPERMITTED
;
80 /* check parameters */
83 || (textType
>= TB_NUM
)
85 code
= BUDB_BADARGUMENT
;
89 /* start the transaction */
90 code
= InitRPC(&ut
, LOCKWRITE
, 1);
94 /* fetch the lock state */
95 if (checkLockHandle(ut
, lockHandle
) == 0) {
96 code
= BUDB_NOTLOCKED
;
100 tbPtr
= &db
.h
.textBlock
[textType
];
102 if ((ntohl(tbPtr
->size
) > 0)
103 && (offset
>= ntohl(tbPtr
->size
))
105 code
= BUDB_BADARGUMENT
;
109 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr
->size
));
111 /* compute minimum of remaining text or user buffer */
112 textRemaining
= ntohl(tbPtr
->size
) - offset
;
113 transferSize
= min(textRemaining
, maxLength
);
115 /* allocate the transfer storage */
116 if (transferSize
<= 0) {
117 charListPtr
->charListT_len
= 0L;
118 charListPtr
->charListT_val
= NULL
;
120 charListPtr
->charListT_len
= transferSize
;
121 charListPtr
->charListT_val
= malloc(transferSize
);
122 if (charListPtr
->charListT_val
== 0)
126 textPtr
= charListPtr
->charListT_val
;
127 *nextOffset
= offset
+ transferSize
;
129 /* setup the datablock. read and discard all blocks up to the one the
132 nblocks
= offset
/ BLOCK_DATA_SIZE
;
133 lastBlockAddr
= ntohl(tbPtr
->textAddr
);
136 code
= dbread(ut
, lastBlockAddr
, (char *)&block
, sizeof(block
));
139 lastBlockAddr
= ntohl(block
.h
.next
);
142 while (transferSize
> 0) {
143 code
= dbread(ut
, lastBlockAddr
, (char *)&block
, sizeof(block
));
147 LogDebug(5, "fetched block %d\n", lastBlockAddr
);
149 /* compute the data size to extract */
150 blockOffset
= offset
% BLOCK_DATA_SIZE
;
151 textRemaining
= BLOCK_DATA_SIZE
- blockOffset
;
152 chunkSize
= min(textRemaining
, transferSize
);
154 memcpy(textPtr
, &block
.a
[blockOffset
], chunkSize
);
156 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
158 transferSize
-= chunkSize
;
160 textPtr
+= chunkSize
;
163 /* setup lastBlockAddr */
164 lastBlockAddr
= ntohl(block
.h
.next
);
168 if (*nextOffset
== ntohl(tbPtr
->size
)) {
174 code
= ubik_EndTrans(ut
);
175 /* printf("in error exit, code=%ld\n", code); */
179 charListPtr
->charListT_len
= 0;
180 charListPtr
->charListT_val
= NULL
;
185 /* printf("in abort exit, code=%ld\n", code); */
190 freeOldBlockChain(struct ubik_trans
*ut
, dbadr diskAddr
)
192 struct blockHeader blockHeader
;
196 while (diskAddr
!= 0) {
197 /* read in the header */
199 dbread(ut
, diskAddr
, (char *)&blockHeader
, sizeof(blockHeader
));
202 nextDiskAddr
= ntohl(blockHeader
.next
);
203 code
= FreeBlock(ut
, &blockHeader
, diskAddr
);
206 diskAddr
= nextDiskAddr
;
212 /* BUDB_GetTextVersion
213 * get the version number for the specified text block
217 SBUDB_GetTextVersion(struct rx_call
*call
, afs_int32 textType
,
218 afs_uint32
*tversion
)
222 code
= GetTextVersion(call
, textType
, tversion
);
223 osi_auditU(call
, BUDB_GetTxVEvent
, code
, AUD_LONG
, textType
, AUD_END
);
228 GetTextVersion(struct rx_call
*call
, afs_int32 textType
,
229 afs_uint32
*tversion
)
232 struct ubik_trans
*ut
;
234 if (callPermitted(call
) == 0)
235 return (BUDB_NOTPERMITTED
);
237 if ((textType
< 0) || (textType
>= TB_NUM
))
238 return (BUDB_BADARGUMENT
);
240 code
= InitRPC(&ut
, LOCKREAD
, 1);
244 *tversion
= ntohl(db
.h
.textBlock
[textType
].version
);
245 code
= ubik_EndTrans(ut
);
250 * next - next disk addr
251 * host/network ordering????
256 * charListPtr storage automatically malloced and freed
260 SBUDB_SaveText(struct rx_call
*call
, afs_uint32 lockHandle
,
261 afs_int32 textType
, afs_int32 offset
, afs_int32 flags
,
262 charListT
*charListPtr
)
266 code
= SaveText(call
, lockHandle
, textType
, offset
, flags
, charListPtr
);
267 osi_auditU(call
, BUDB_SavTxtEvent
, code
, AUD_LONG
, textType
, AUD_END
);
272 SaveText(struct rx_call
*call
, afs_uint32 lockHandle
, afs_int32 textType
,
273 afs_int32 offset
, afs_int32 flags
, charListT
*charListPtr
)
275 struct ubik_trans
*ut
;
276 struct block diskBlock
;
278 afs_int32 remainingInBlock
, chunkSize
;
279 struct textBlock
*tbPtr
;
280 afs_int32 textLength
= charListPtr
->charListT_len
;
281 char *textptr
= charListPtr
->charListT_val
;
284 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType
, offset
,
287 if (callPermitted(call
) == 0)
288 return (BUDB_NOTPERMITTED
);
290 if ((textLength
> BLOCK_DATA_SIZE
) || (offset
< 0))
291 return (BUDB_BADARGUMENT
);
293 code
= InitRPC(&ut
, LOCKWRITE
, 1);
297 /* fetch the lock state */
298 if (checkLockHandle(ut
, lockHandle
) == 0)
299 ABORT(BUDB_NOTLOCKED
);
301 if ((textType
< 0) || (textType
>= TB_NUM
))
302 ABORT(BUDB_BADARGUMENT
);
304 tbPtr
= &db
.h
.textBlock
[textType
];
307 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
308 lockHandle
, textType
, offset
, flags
, textLength
);
311 /* release any blocks from previous transactions */
312 diskBlockAddr
= ntohl(tbPtr
->newTextAddr
);
313 freeOldBlockChain(ut
, diskBlockAddr
);
316 code
= AllocBlock(ut
, &diskBlock
, &diskBlockAddr
);
320 LogDebug(5, "allocated block %d\n", diskBlockAddr
);
323 diskBlock
.h
.type
= text_BLOCK
;
325 /* save it in the database header */
327 tbPtr
->newTextAddr
= htonl(diskBlockAddr
);
328 dbwrite(ut
, (char *)tbPtr
- (char *)&db
.h
, (char *)tbPtr
,
329 sizeof(struct textBlock
));
332 tbPtr
->newTextAddr
= 0;
335 /* non-zero offset */
338 if (offset
!= ntohl(tbPtr
->newsize
))
339 ABORT(BUDB_BADARGUMENT
);
341 /* locate the block to which offset refers */
342 nblocks
= offset
/ BLOCK_DATA_SIZE
;
344 diskBlockAddr
= ntohl(tbPtr
->newTextAddr
);
345 if (diskBlockAddr
== 0)
346 ABORT(BUDB_BADARGUMENT
);
349 dbread(ut
, diskBlockAddr
, (char *)&diskBlock
, sizeof(diskBlock
));
354 diskBlockAddr
= ntohl(diskBlock
.h
.next
);
356 dbread(ut
, diskBlockAddr
, (char *)&diskBlock
,
363 /* diskBlock and diskBlockAddr now point to the last block in the chain */
366 /* compute the transfer size */
367 remainingInBlock
= (BLOCK_DATA_SIZE
- (offset
% BLOCK_DATA_SIZE
));
368 chunkSize
= min(remainingInBlock
, textLength
);
370 /* copy in the data */
371 memcpy(&diskBlock
.a
[offset
% BLOCK_DATA_SIZE
], textptr
, chunkSize
);
373 /* LogDebug(5, "text is %s\n", textptr); */
375 textLength
-= chunkSize
;
376 textptr
+= chunkSize
;
378 tbPtr
->newsize
= htonl(ntohl(tbPtr
->newsize
) + chunkSize
);
380 if (textLength
> 0) {
381 afs_int32 prevBlockAddr
;
382 afs_int32 linkOffset
;
385 /* have to add another block to the chain */
388 dbwrite(ut
, diskBlockAddr
, (char *)&diskBlock
,
393 prevBlockAddr
= (afs_int32
) diskBlockAddr
;
394 code
= AllocBlock(ut
, &diskBlock
, &diskBlockAddr
);
398 LogDebug(5, "allocated block %d\n", diskBlockAddr
);
401 diskBlock
.h
.type
= text_BLOCK
;
403 /* now have to update the previous block's link */
405 (afs_int32
) ((char*)& diskBlock
.h
.next
- (char*)& diskBlock
);
406 linkValue
= htonl(diskBlockAddr
);
409 dbwrite(ut
, (afs_int32
) prevBlockAddr
+ linkOffset
,
410 (char *)&linkValue
, sizeof(afs_int32
));
414 /* just write the old block */
416 dbwrite(ut
, diskBlockAddr
, (char *)&diskBlock
,
423 if (flags
& BUDB_TEXT_COMPLETE
) { /* done */
424 /* this was the last chunk of text */
425 diskBlockAddr
= ntohl(tbPtr
->textAddr
);
426 freeOldBlockChain(ut
, diskBlockAddr
);
428 tbPtr
->textAddr
= tbPtr
->newTextAddr
;
429 tbPtr
->newTextAddr
= 0;
430 tbPtr
->size
= tbPtr
->newsize
;
432 tbPtr
->version
= htonl(ntohl(tbPtr
->version
) + 1);
434 /* saveTextToFile(ut, tbPtr); */
437 /* update size and other text header info */
439 dbwrite(ut
, (char *)tbPtr
- (char *)&db
.h
, (char *)tbPtr
,
440 sizeof(struct textBlock
));
445 code
= ubik_EndTrans(ut
);
455 saveTextToFile(struct ubik_trans
*ut
, struct textBlock
*tbPtr
)
460 afs_int32 size
, totalSize
, chunkSize
;
463 sprintf(filename
, "%s/%s", gettmpdir(), "dbg_XXXXXX");
465 fid
= mkstemp(filename
);
466 totalSize
= size
= ntohl(tbPtr
->size
);
467 blockAddr
= ntohl(tbPtr
->textAddr
);
469 chunkSize
= min(BLOCK_DATA_SIZE
, size
);
470 dbread(ut
, blockAddr
, (char *)&block
, sizeof(block
));
471 if (write(fid
, &block
.a
[0], chunkSize
) < 0)
473 blockAddr
= ntohl(block
.h
.next
);
478 printf("Wrote partial debug file (%ld bytes out of %ld)\n",
479 (long)(totalSize
- size
), (long)totalSize
);
481 printf("wrote debug file %s\n", filename
);