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>
20 #include <netinet/in.h>
22 #include <sys/param.h>
25 #include <sys/types.h>
27 #include <afs/bubasics.h>
28 #include "budb_errs.h"
30 #include "error_macros.h"
31 #include "budb_internal.h"
32 #include "afs/audit.h"
33 #include <afs/afsutil.h>
35 /* --------------------------------
36 * interface & support code to manage text blocks within the
38 * --------------------------------
43 * routine mallocs storage for charListPtr, freed by stub
46 afs_int32 GetText(struct rx_call *, afs_uint32, afs_int32, afs_int32,
47 afs_int32, afs_int32 *, charListT *);
48 afs_int32 GetTextVersion(struct rx_call *, afs_int32, afs_uint32 *);
49 afs_int32 SaveText(struct rx_call *, afs_uint32, afs_int32, afs_int32,
50 afs_int32, charListT *);
53 SBUDB_GetText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType,
54 afs_int32 maxLength, afs_int32 offset, afs_int32 *nextOffset,
55 charListT *charListPtr)
60 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
62 osi_auditU(call, BUDB_GetTxtEvent, code, AUD_LONG, textType, AUD_END);
67 GetText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType,
68 afs_int32 maxLength, afs_int32 offset, afs_int32 *nextOffset,
69 charListT *charListPtr)
71 struct ubik_trans *ut = 0;
73 afs_int32 transferSize, chunkSize;
74 afs_int32 blockOffset;
77 struct textBlock *tbPtr;
78 afs_int32 textRemaining;
82 LogDebug(5, "GetText: type %d, offset %d, nextOffset %"AFS_PTR_FMT
83 ", maxLength %d\n", textType, offset, nextOffset, maxLength);
85 if (callPermitted(call) == 0) {
86 code = BUDB_NOTPERMITTED;
90 /* check parameters */
93 || (textType >= TB_NUM)
95 code = BUDB_BADARGUMENT;
99 /* start the transaction */
100 code = InitRPC(&ut, LOCKWRITE, 1);
104 /* fetch the lock state */
105 if (checkLockHandle(ut, lockHandle) == 0) {
106 code = BUDB_NOTLOCKED;
110 tbPtr = &db.h.textBlock[textType];
112 if ((ntohl(tbPtr->size) > 0)
113 && (offset >= ntohl(tbPtr->size))
115 code = BUDB_BADARGUMENT;
119 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr->size));
121 /* compute minimum of remaining text or user buffer */
122 textRemaining = ntohl(tbPtr->size) - offset;
123 transferSize = MIN(textRemaining, maxLength);
125 /* allocate the transfer storage */
126 if (transferSize <= 0) {
127 charListPtr->charListT_len = 0L;
128 charListPtr->charListT_val = NULL;
130 charListPtr->charListT_len = transferSize;
131 charListPtr->charListT_val = (char *)malloc(transferSize);
132 if (charListPtr->charListT_val == 0)
136 textPtr = charListPtr->charListT_val;
137 *nextOffset = offset + transferSize;
139 /* setup the datablock. read and discard all blocks up to the one the
142 nblocks = offset / BLOCK_DATA_SIZE;
143 lastBlockAddr = ntohl(tbPtr->textAddr);
146 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
149 lastBlockAddr = ntohl(block.h.next);
152 while (transferSize > 0) {
153 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
157 LogDebug(5, "fetched block %d\n", lastBlockAddr);
159 /* compute the data size to extract */
160 blockOffset = offset % BLOCK_DATA_SIZE;
161 textRemaining = BLOCK_DATA_SIZE - blockOffset;
162 chunkSize = min(textRemaining, transferSize);
164 memcpy(textPtr, &block.a[blockOffset], chunkSize);
166 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
168 transferSize -= chunkSize;
170 textPtr += chunkSize;
173 /* setup lastBlockAddr */
174 lastBlockAddr = ntohl(block.h.next);
178 if (*nextOffset == ntohl(tbPtr->size)) {
184 code = ubik_EndTrans(ut);
185 /* printf("in error exit, code=%ld\n", code); */
189 charListPtr->charListT_len = 0;
190 charListPtr->charListT_val = (char *)malloc(0);
195 /* printf("in abort exit, code=%ld\n", code); */
200 freeOldBlockChain(struct ubik_trans *ut, dbadr diskAddr)
202 struct blockHeader blockHeader;
206 while (diskAddr != 0) {
207 /* read in the header */
209 dbread(ut, diskAddr, (char *)&blockHeader, sizeof(blockHeader));
212 nextDiskAddr = ntohl(blockHeader.next);
213 code = FreeBlock(ut, &blockHeader, diskAddr);
216 diskAddr = nextDiskAddr;
222 /* BUDB_GetTextVersion
223 * get the version number for the specified text block
227 SBUDB_GetTextVersion(struct rx_call *call, afs_int32 textType,
228 afs_uint32 *tversion)
232 code = GetTextVersion(call, textType, tversion);
233 osi_auditU(call, BUDB_GetTxVEvent, code, AUD_LONG, textType, AUD_END);
238 GetTextVersion(struct rx_call *call, afs_int32 textType,
239 afs_uint32 *tversion)
242 struct ubik_trans *ut;
244 if (callPermitted(call) == 0)
245 return (BUDB_NOTPERMITTED);
247 if ((textType < 0) || (textType >= TB_NUM))
248 return (BUDB_BADARGUMENT);
250 code = InitRPC(&ut, LOCKREAD, 1);
254 *tversion = ntohl(db.h.textBlock[textType].version);
255 code = ubik_EndTrans(ut);
260 * next - next disk addr
261 * host/network ordering????
266 * charListPtr storage automatically malloced and freed
270 SBUDB_SaveText(struct rx_call *call, afs_uint32 lockHandle,
271 afs_int32 textType, afs_int32 offset, afs_int32 flags,
272 charListT *charListPtr)
276 code = SaveText(call, lockHandle, textType, offset, flags, charListPtr);
277 osi_auditU(call, BUDB_SavTxtEvent, code, AUD_LONG, textType, AUD_END);
282 SaveText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType,
283 afs_int32 offset, afs_int32 flags, charListT *charListPtr)
285 struct ubik_trans *ut;
286 struct block diskBlock;
288 afs_int32 remainingInBlock, chunkSize;
289 struct textBlock *tbPtr;
290 afs_int32 textLength = charListPtr->charListT_len;
291 char *textptr = charListPtr->charListT_val;
294 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType, offset,
297 if (callPermitted(call) == 0)
298 return (BUDB_NOTPERMITTED);
300 if ((textLength > BLOCK_DATA_SIZE) || (offset < 0))
301 return (BUDB_BADARGUMENT);
303 code = InitRPC(&ut, LOCKWRITE, 1);
307 /* fetch the lock state */
308 if (checkLockHandle(ut, lockHandle) == 0)
309 ABORT(BUDB_NOTLOCKED);
311 if ((textType < 0) || (textType >= TB_NUM))
312 ABORT(BUDB_BADARGUMENT);
314 tbPtr = &db.h.textBlock[textType];
317 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
318 lockHandle, textType, offset, flags, textLength);
321 /* release any blocks from previous transactions */
322 diskBlockAddr = ntohl(tbPtr->newTextAddr);
323 freeOldBlockChain(ut, diskBlockAddr);
326 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
330 LogDebug(5, "allocated block %d\n", diskBlockAddr);
333 diskBlock.h.type = text_BLOCK;
335 /* save it in the database header */
337 tbPtr->newTextAddr = htonl(diskBlockAddr);
338 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
339 sizeof(struct textBlock));
342 tbPtr->newTextAddr = 0;
345 /* non-zero offset */
348 if (offset != ntohl(tbPtr->newsize))
349 ABORT(BUDB_BADARGUMENT);
351 /* locate the block to which offset refers */
352 nblocks = offset / BLOCK_DATA_SIZE;
354 diskBlockAddr = ntohl(tbPtr->newTextAddr);
355 if (diskBlockAddr == 0)
356 ABORT(BUDB_BADARGUMENT);
359 dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
364 diskBlockAddr = ntohl(diskBlock.h.next);
366 dbread(ut, diskBlockAddr, (char *)&diskBlock,
373 /* diskBlock and diskBlockAddr now point to the last block in the chain */
376 /* compute the transfer size */
377 remainingInBlock = (BLOCK_DATA_SIZE - (offset % BLOCK_DATA_SIZE));
378 chunkSize = MIN(remainingInBlock, textLength);
380 /* copy in the data */
381 memcpy(&diskBlock.a[offset % BLOCK_DATA_SIZE], textptr, chunkSize);
383 /* LogDebug(5, "text is %s\n", textptr); */
385 textLength -= chunkSize;
386 textptr += chunkSize;
388 tbPtr->newsize = htonl(ntohl(tbPtr->newsize) + chunkSize);
390 if (textLength > 0) {
391 afs_int32 prevBlockAddr;
392 afs_int32 linkOffset;
395 /* have to add another block to the chain */
398 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
403 prevBlockAddr = (afs_int32) diskBlockAddr;
404 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
408 LogDebug(5, "allocated block %d\n", diskBlockAddr);
411 diskBlock.h.type = text_BLOCK;
413 /* now have to update the previous block's link */
415 (afs_int32) ((char*)& diskBlock.h.next - (char*)& diskBlock);
416 linkValue = htonl(diskBlockAddr);
419 dbwrite(ut, (afs_int32) prevBlockAddr + linkOffset,
420 (char *)&linkValue, sizeof(afs_int32));
424 /* just write the old block */
426 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
433 if (flags & BUDB_TEXT_COMPLETE) { /* done */
434 /* this was the last chunk of text */
435 diskBlockAddr = ntohl(tbPtr->textAddr);
436 freeOldBlockChain(ut, diskBlockAddr);
438 tbPtr->textAddr = tbPtr->newTextAddr;
439 tbPtr->newTextAddr = 0;
440 tbPtr->size = tbPtr->newsize;
442 tbPtr->version = htonl(ntohl(tbPtr->version) + 1);
444 /* saveTextToFile(ut, tbPtr); */
447 /* update size and other text header info */
449 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
450 sizeof(struct textBlock));
455 code = ubik_EndTrans(ut);
465 saveTextToFile(struct ubik_trans *ut, struct textBlock *tbPtr)
470 afs_int32 size, chunkSize;
473 sprintf(filename, "%s/%s", gettmpdir(), "dbg_XXXXXX");
475 fid = mkstemp(filename);
476 size = ntohl(tbPtr->size);
477 blockAddr = ntohl(tbPtr->textAddr);
479 chunkSize = MIN(BLOCK_DATA_SIZE, size);
480 dbread(ut, blockAddr, (char *)&block, sizeof(block));
481 write(fid, &block.a[0], chunkSize);
482 blockAddr = ntohl(block.h.next);
486 printf("wrote debug file %s\n", filename);
490 #if (defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
494 * st - string containing template for a tmp file name
497 * 0-n - open file descriptor
499 * 1) missing in Ultrix, HP/UX and AIX 221 environment
500 * 2) iterate some number of times to alleviate the race?
508 #ifdef AFS_LINUX20_ENV
509 retval = open(mkstemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);
511 retval = open(mktemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);