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>
32 #include <sys/types.h>
35 #include <afs/bubasics.h>
36 #include "budb_errs.h"
38 #include "error_macros.h"
39 #include "afs/audit.h"
40 #include <afs/afsutil.h>
42 /* --------------------------------
43 * interface & support code to manage text blocks within the
45 * --------------------------------
50 * routine mallocs storage for charListPtr, freed by stub
53 afs_int32 GetText(), GetTextVersion(), SaveText();
56 SBUDB_GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
59 afs_uint32 lockHandle;
63 afs_int32 *nextOffset;
64 charListT *charListPtr;
69 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
71 osi_auditU(call, BUDB_GetTxtEvent, code, AUD_LONG, textType, AUD_END);
76 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
79 afs_uint32 lockHandle;
83 afs_int32 *nextOffset;
84 charListT *charListPtr;
86 struct ubik_trans *ut = 0;
88 afs_int32 transferSize, chunkSize;
89 afs_int32 blockOffset;
92 struct textBlock *tbPtr;
93 afs_int32 textRemaining;
97 LogDebug(5, "GetText: type %d, offset %d, nextOffset %d, maxLength %d\n",
98 textType, offset, nextOffset, maxLength);
100 if (callPermitted(call) == 0) {
101 code = BUDB_NOTPERMITTED;
105 /* check parameters */
108 || (textType >= TB_NUM)
110 code = BUDB_BADARGUMENT;
114 /* start the transaction */
115 code = InitRPC(&ut, LOCKWRITE, 1);
119 /* fetch the lock state */
120 if (checkLockHandle(ut, lockHandle) == 0) {
121 code = BUDB_NOTLOCKED;
125 tbPtr = &db.h.textBlock[textType];
127 if ((ntohl(tbPtr->size) > 0)
128 && (offset >= ntohl(tbPtr->size))
130 code = BUDB_BADARGUMENT;
134 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr->size));
136 /* compute minimum of remaining text or user buffer */
137 textRemaining = ntohl(tbPtr->size) - offset;
138 transferSize = MIN(textRemaining, maxLength);
140 /* allocate the transfer storage */
141 if (transferSize <= 0) {
142 charListPtr->charListT_len = 0L;
143 charListPtr->charListT_val = NULL;
145 charListPtr->charListT_len = transferSize;
146 charListPtr->charListT_val = (char *)malloc(transferSize);
147 if (charListPtr->charListT_val == 0)
151 textPtr = charListPtr->charListT_val;
152 *nextOffset = offset + transferSize;
154 /* setup the datablock. read and discard all blocks up to the one the
157 nblocks = offset / BLOCK_DATA_SIZE;
158 lastBlockAddr = ntohl(tbPtr->textAddr);
161 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
164 lastBlockAddr = ntohl(block.h.next);
167 while (transferSize > 0) {
168 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
172 LogDebug(5, "fetched block %d\n", lastBlockAddr);
174 /* compute the data size to extract */
175 blockOffset = offset % BLOCK_DATA_SIZE;
176 textRemaining = BLOCK_DATA_SIZE - blockOffset;
177 chunkSize = min(textRemaining, transferSize);
179 memcpy(textPtr, &block.a[blockOffset], chunkSize);
181 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
183 transferSize -= chunkSize;
185 textPtr += chunkSize;
188 /* setup lastBlockAddr */
189 lastBlockAddr = ntohl(block.h.next);
193 if (*nextOffset == ntohl(tbPtr->size)) {
199 code = ubik_EndTrans(ut);
200 /* printf("in error exit, code=%ld\n", code); */
204 charListPtr->charListT_len = 0;
205 charListPtr->charListT_val = (char *)malloc(0);
210 /* printf("in abort exit, code=%ld\n", code); */
214 freeOldBlockChain(ut, diskAddr)
215 struct ubik_trans *ut;
218 struct blockHeader blockHeader;
222 while (diskAddr != 0) {
223 /* read in the header */
225 dbread(ut, diskAddr, (char *)&blockHeader, sizeof(blockHeader));
228 nextDiskAddr = ntohl(blockHeader.next);
229 code = FreeBlock(ut, &blockHeader, diskAddr);
232 diskAddr = nextDiskAddr;
238 /* BUDB_GetTextVersion
239 * get the version number for the specified text block
243 SBUDB_GetTextVersion(call, textType, tversion)
244 struct rx_call *call;
246 afs_uint32 *tversion;
250 code = GetTextVersion(call, textType, tversion);
251 osi_auditU(call, BUDB_GetTxVEvent, code, AUD_LONG, textType, AUD_END);
256 GetTextVersion(call, textType, tversion)
257 struct rx_call *call;
259 afs_uint32 *tversion;
262 struct ubik_trans *ut;
264 if (callPermitted(call) == 0)
265 return (BUDB_NOTPERMITTED);
267 if ((textType < 0) || (textType >= TB_NUM))
268 return (BUDB_BADARGUMENT);
270 code = InitRPC(&ut, LOCKREAD, 1);
274 *tversion = ntohl(db.h.textBlock[textType].version);
275 code = ubik_EndTrans(ut);
280 * next - next disk addr
281 * host/network ordering????
286 * charListPtr storage automatically malloced and freed
290 SBUDB_SaveText(call, lockHandle, textType, offset, flags, charListPtr)
291 struct rx_call *call;
292 afs_uint32 lockHandle;
296 charListT *charListPtr;
300 code = SaveText(call, lockHandle, textType, offset, flags, charListPtr);
301 osi_auditU(call, BUDB_SavTxtEvent, code, AUD_LONG, textType, AUD_END);
306 SaveText(call, lockHandle, textType, offset, flags, charListPtr)
307 struct rx_call *call;
308 afs_uint32 lockHandle;
312 charListT *charListPtr;
314 struct ubik_trans *ut;
315 struct block diskBlock;
317 afs_int32 remainingInBlock, chunkSize;
318 struct textBlock *tbPtr;
319 afs_int32 textLength = charListPtr->charListT_len;
320 char *textptr = charListPtr->charListT_val;
323 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType, offset,
326 if (callPermitted(call) == 0)
327 return (BUDB_NOTPERMITTED);
329 if ((textLength > BLOCK_DATA_SIZE) || (offset < 0))
330 return (BUDB_BADARGUMENT);
332 code = InitRPC(&ut, LOCKWRITE, 1);
336 /* fetch the lock state */
337 if (checkLockHandle(ut, lockHandle) == 0)
338 ABORT(BUDB_NOTLOCKED);
340 if ((textType < 0) || (textType >= TB_NUM))
341 ABORT(BUDB_BADARGUMENT);
343 tbPtr = &db.h.textBlock[textType];
346 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
347 lockHandle, textType, offset, flags, textLength);
350 /* release any blocks from previous transactions */
351 diskBlockAddr = ntohl(tbPtr->newTextAddr);
352 freeOldBlockChain(ut, diskBlockAddr);
355 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
359 LogDebug(5, "allocated block %d\n", diskBlockAddr);
362 diskBlock.h.type = text_BLOCK;
364 /* save it in the database header */
366 tbPtr->newTextAddr = htonl(diskBlockAddr);
367 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
368 sizeof(struct textBlock));
371 tbPtr->newTextAddr = 0;
374 /* non-zero offset */
377 if (offset != ntohl(tbPtr->newsize))
378 ABORT(BUDB_BADARGUMENT);
380 /* locate the block to which offset refers */
381 nblocks = offset / BLOCK_DATA_SIZE;
383 diskBlockAddr = ntohl(tbPtr->newTextAddr);
384 if (diskBlockAddr == 0)
385 ABORT(BUDB_BADARGUMENT);
388 dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
393 diskBlockAddr = ntohl(diskBlock.h.next);
395 dbread(ut, diskBlockAddr, (char *)&diskBlock,
402 /* diskBlock and diskBlockAddr now point to the last block in the chain */
405 /* compute the transfer size */
406 remainingInBlock = (BLOCK_DATA_SIZE - (offset % BLOCK_DATA_SIZE));
407 chunkSize = MIN(remainingInBlock, textLength);
409 /* copy in the data */
410 memcpy(&diskBlock.a[offset % BLOCK_DATA_SIZE], textptr, chunkSize);
412 /* LogDebug(5, "text is %s\n", textptr); */
414 textLength -= chunkSize;
415 textptr += chunkSize;
417 tbPtr->newsize = htonl(ntohl(tbPtr->newsize) + chunkSize);
419 if (textLength > 0) {
420 afs_int32 prevBlockAddr;
421 afs_int32 linkOffset;
424 /* have to add another block to the chain */
427 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
432 prevBlockAddr = (afs_int32) diskBlockAddr;
433 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
437 LogDebug(5, "allocated block %d\n", diskBlockAddr);
440 diskBlock.h.type = text_BLOCK;
442 /* now have to update the previous block's link */
444 (afs_int32) & diskBlock.h.next - (afs_int32) & diskBlock;
445 linkValue = htonl(diskBlockAddr);
448 dbwrite(ut, (afs_int32) prevBlockAddr + linkOffset,
449 (char *)&linkValue, sizeof(afs_int32));
453 /* just write the old block */
455 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
462 if (flags & BUDB_TEXT_COMPLETE) { /* done */
463 /* this was the last chunk of text */
464 diskBlockAddr = ntohl(tbPtr->textAddr);
465 freeOldBlockChain(ut, diskBlockAddr);
467 tbPtr->textAddr = tbPtr->newTextAddr;
468 tbPtr->newTextAddr = 0;
469 tbPtr->size = tbPtr->newsize;
471 tbPtr->version = htonl(ntohl(tbPtr->version) + 1);
473 /* saveTextToFile(ut, tbPtr); */
476 /* update size and other text header info */
478 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
479 sizeof(struct textBlock));
484 code = ubik_EndTrans(ut);
494 saveTextToFile(ut, tbPtr)
495 struct ubik_trans *ut;
496 struct textBlock *tbPtr;
502 afs_int32 size, chunkSize;
505 sprintf(filename, "%s/%s", gettmpdir(), "dbg_XXXXXX");
507 fid = mkstemp(filename);
508 size = ntohl(tbPtr->size);
509 blockAddr = ntohl(tbPtr->textAddr);
511 chunkSize = MIN(BLOCK_DATA_SIZE, size);
512 dbread(ut, blockAddr, (char *)&block, sizeof(block));
513 write(fid, &block.a[0], chunkSize);
514 blockAddr = ntohl(block.h.next);
518 printf("wrote debug file %s\n", filename);
522 #if (defined(AFS_DEC_ENV) || defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
526 * st - string containing template for a tmp file name
529 * 0-n - open file descriptor
531 * 1) missing in Ultrix, HP/UX and AIX 221 environment
532 * 2) iterate some number of times to alleviate the race?
541 #ifdef AFS_LINUX20_ENV
542 retval = open(mkstemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);
544 retval = open(mktemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);