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>
21 #include <netinet/in.h>
23 #include <sys/param.h>
26 #include <sys/types.h>
28 #include <afs/bubasics.h>
29 #include "budb_errs.h"
31 #include "error_macros.h"
32 #include "budb_prototypes.h"
33 #include "afs/audit.h"
34 #include <afs/afsutil.h>
36 /* --------------------------------
37 * interface & support code to manage text blocks within the
39 * --------------------------------
44 * routine mallocs storage for charListPtr, freed by stub
47 afs_int32 GetText(struct rx_call *, afs_uint32, afs_int32, afs_int32,
48 afs_int32, afs_int32 *, charListT *);
49 afs_int32 GetTextVersion(struct rx_call *, afs_int32, afs_uint32 *);
50 afs_int32 SaveText(struct rx_call *, afs_uint32, afs_int32, afs_int32,
51 afs_int32, charListT *);
54 SBUDB_GetText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType,
55 afs_int32 maxLength, afs_int32 offset, afs_int32 *nextOffset,
56 charListT *charListPtr)
61 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
63 osi_auditU(call, BUDB_GetTxtEvent, code, AUD_LONG, textType, AUD_END);
68 GetText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType,
69 afs_int32 maxLength, afs_int32 offset, afs_int32 *nextOffset,
70 charListT *charListPtr)
72 struct ubik_trans *ut = 0;
74 afs_int32 transferSize, chunkSize;
75 afs_int32 blockOffset;
78 struct textBlock *tbPtr;
79 afs_int32 textRemaining;
83 LogDebug(5, "GetText: type %d, offset %d, nextOffset %d, maxLength %d\n",
84 textType, offset, nextOffset, maxLength);
86 if (callPermitted(call) == 0) {
87 code = BUDB_NOTPERMITTED;
91 /* check parameters */
94 || (textType >= TB_NUM)
96 code = BUDB_BADARGUMENT;
100 /* start the transaction */
101 code = InitRPC(&ut, LOCKWRITE, 1);
105 /* fetch the lock state */
106 if (checkLockHandle(ut, lockHandle) == 0) {
107 code = BUDB_NOTLOCKED;
111 tbPtr = &db.h.textBlock[textType];
113 if ((ntohl(tbPtr->size) > 0)
114 && (offset >= ntohl(tbPtr->size))
116 code = BUDB_BADARGUMENT;
120 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr->size));
122 /* compute minimum of remaining text or user buffer */
123 textRemaining = ntohl(tbPtr->size) - offset;
124 transferSize = MIN(textRemaining, maxLength);
126 /* allocate the transfer storage */
127 if (transferSize <= 0) {
128 charListPtr->charListT_len = 0L;
129 charListPtr->charListT_val = NULL;
131 charListPtr->charListT_len = transferSize;
132 charListPtr->charListT_val = (char *)malloc(transferSize);
133 if (charListPtr->charListT_val == 0)
137 textPtr = charListPtr->charListT_val;
138 *nextOffset = offset + transferSize;
140 /* setup the datablock. read and discard all blocks up to the one the
143 nblocks = offset / BLOCK_DATA_SIZE;
144 lastBlockAddr = ntohl(tbPtr->textAddr);
147 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
150 lastBlockAddr = ntohl(block.h.next);
153 while (transferSize > 0) {
154 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
158 LogDebug(5, "fetched block %d\n", lastBlockAddr);
160 /* compute the data size to extract */
161 blockOffset = offset % BLOCK_DATA_SIZE;
162 textRemaining = BLOCK_DATA_SIZE - blockOffset;
163 chunkSize = min(textRemaining, transferSize);
165 memcpy(textPtr, &block.a[blockOffset], chunkSize);
167 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
169 transferSize -= chunkSize;
171 textPtr += chunkSize;
174 /* setup lastBlockAddr */
175 lastBlockAddr = ntohl(block.h.next);
179 if (*nextOffset == ntohl(tbPtr->size)) {
185 code = ubik_EndTrans(ut);
186 /* printf("in error exit, code=%ld\n", code); */
190 charListPtr->charListT_len = 0;
191 charListPtr->charListT_val = (char *)malloc(0);
196 /* printf("in abort exit, code=%ld\n", code); */
201 freeOldBlockChain(struct ubik_trans *ut, dbadr diskAddr)
203 struct blockHeader blockHeader;
207 while (diskAddr != 0) {
208 /* read in the header */
210 dbread(ut, diskAddr, (char *)&blockHeader, sizeof(blockHeader));
213 nextDiskAddr = ntohl(blockHeader.next);
214 code = FreeBlock(ut, &blockHeader, diskAddr);
217 diskAddr = nextDiskAddr;
223 /* BUDB_GetTextVersion
224 * get the version number for the specified text block
228 SBUDB_GetTextVersion(struct rx_call *call, afs_int32 textType,
229 afs_uint32 *tversion)
233 code = GetTextVersion(call, textType, tversion);
234 osi_auditU(call, BUDB_GetTxVEvent, code, AUD_LONG, textType, AUD_END);
239 GetTextVersion(struct rx_call *call, afs_int32 textType,
240 afs_uint32 *tversion)
243 struct ubik_trans *ut;
245 if (callPermitted(call) == 0)
246 return (BUDB_NOTPERMITTED);
248 if ((textType < 0) || (textType >= TB_NUM))
249 return (BUDB_BADARGUMENT);
251 code = InitRPC(&ut, LOCKREAD, 1);
255 *tversion = ntohl(db.h.textBlock[textType].version);
256 code = ubik_EndTrans(ut);
261 * next - next disk addr
262 * host/network ordering????
267 * charListPtr storage automatically malloced and freed
271 SBUDB_SaveText(struct rx_call *call, afs_uint32 lockHandle,
272 afs_int32 textType, afs_int32 offset, afs_int32 flags,
273 charListT *charListPtr)
277 code = SaveText(call, lockHandle, textType, offset, flags, charListPtr);
278 osi_auditU(call, BUDB_SavTxtEvent, code, AUD_LONG, textType, AUD_END);
283 SaveText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType,
284 afs_int32 offset, afs_int32 flags, charListT *charListPtr)
286 struct ubik_trans *ut;
287 struct block diskBlock;
289 afs_int32 remainingInBlock, chunkSize;
290 struct textBlock *tbPtr;
291 afs_int32 textLength = charListPtr->charListT_len;
292 char *textptr = charListPtr->charListT_val;
295 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType, offset,
298 if (callPermitted(call) == 0)
299 return (BUDB_NOTPERMITTED);
301 if ((textLength > BLOCK_DATA_SIZE) || (offset < 0))
302 return (BUDB_BADARGUMENT);
304 code = InitRPC(&ut, LOCKWRITE, 1);
308 /* fetch the lock state */
309 if (checkLockHandle(ut, lockHandle) == 0)
310 ABORT(BUDB_NOTLOCKED);
312 if ((textType < 0) || (textType >= TB_NUM))
313 ABORT(BUDB_BADARGUMENT);
315 tbPtr = &db.h.textBlock[textType];
318 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
319 lockHandle, textType, offset, flags, textLength);
322 /* release any blocks from previous transactions */
323 diskBlockAddr = ntohl(tbPtr->newTextAddr);
324 freeOldBlockChain(ut, diskBlockAddr);
327 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
331 LogDebug(5, "allocated block %d\n", diskBlockAddr);
334 diskBlock.h.type = text_BLOCK;
336 /* save it in the database header */
338 tbPtr->newTextAddr = htonl(diskBlockAddr);
339 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
340 sizeof(struct textBlock));
343 tbPtr->newTextAddr = 0;
346 /* non-zero offset */
349 if (offset != ntohl(tbPtr->newsize))
350 ABORT(BUDB_BADARGUMENT);
352 /* locate the block to which offset refers */
353 nblocks = offset / BLOCK_DATA_SIZE;
355 diskBlockAddr = ntohl(tbPtr->newTextAddr);
356 if (diskBlockAddr == 0)
357 ABORT(BUDB_BADARGUMENT);
360 dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
365 diskBlockAddr = ntohl(diskBlock.h.next);
367 dbread(ut, diskBlockAddr, (char *)&diskBlock,
374 /* diskBlock and diskBlockAddr now point to the last block in the chain */
377 /* compute the transfer size */
378 remainingInBlock = (BLOCK_DATA_SIZE - (offset % BLOCK_DATA_SIZE));
379 chunkSize = MIN(remainingInBlock, textLength);
381 /* copy in the data */
382 memcpy(&diskBlock.a[offset % BLOCK_DATA_SIZE], textptr, chunkSize);
384 /* LogDebug(5, "text is %s\n", textptr); */
386 textLength -= chunkSize;
387 textptr += chunkSize;
389 tbPtr->newsize = htonl(ntohl(tbPtr->newsize) + chunkSize);
391 if (textLength > 0) {
392 afs_int32 prevBlockAddr;
393 afs_int32 linkOffset;
396 /* have to add another block to the chain */
399 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
404 prevBlockAddr = (afs_int32) diskBlockAddr;
405 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
409 LogDebug(5, "allocated block %d\n", diskBlockAddr);
412 diskBlock.h.type = text_BLOCK;
414 /* now have to update the previous block's link */
416 (afs_int32) ((char*)& diskBlock.h.next - (char*)& diskBlock);
417 linkValue = htonl(diskBlockAddr);
420 dbwrite(ut, (afs_int32) prevBlockAddr + linkOffset,
421 (char *)&linkValue, sizeof(afs_int32));
425 /* just write the old block */
427 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
434 if (flags & BUDB_TEXT_COMPLETE) { /* done */
435 /* this was the last chunk of text */
436 diskBlockAddr = ntohl(tbPtr->textAddr);
437 freeOldBlockChain(ut, diskBlockAddr);
439 tbPtr->textAddr = tbPtr->newTextAddr;
440 tbPtr->newTextAddr = 0;
441 tbPtr->size = tbPtr->newsize;
443 tbPtr->version = htonl(ntohl(tbPtr->version) + 1);
445 /* saveTextToFile(ut, tbPtr); */
448 /* update size and other text header info */
450 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
451 sizeof(struct textBlock));
456 code = ubik_EndTrans(ut);
466 saveTextToFile(struct ubik_trans *ut, struct textBlock *tbPtr)
471 afs_int32 size, chunkSize;
474 sprintf(filename, "%s/%s", gettmpdir(), "dbg_XXXXXX");
476 fid = mkstemp(filename);
477 size = ntohl(tbPtr->size);
478 blockAddr = ntohl(tbPtr->textAddr);
480 chunkSize = MIN(BLOCK_DATA_SIZE, size);
481 dbread(ut, blockAddr, (char *)&block, sizeof(block));
482 write(fid, &block.a[0], chunkSize);
483 blockAddr = ntohl(block.h.next);
487 printf("wrote debug file %s\n", filename);
491 #if (defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
495 * st - string containing template for a tmp file name
498 * 0-n - open file descriptor
500 * 1) missing in Ultrix, HP/UX and AIX 221 environment
501 * 2) iterate some number of times to alleviate the race?
509 #ifdef AFS_LINUX20_ENV
510 retval = open(mkstemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);
512 retval = open(mktemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);