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>
24 #include <sys/types.h>
27 #include <afs/bubasics.h>
28 #include "budb_errs.h"
30 #include "error_macros.h"
31 #include "afs/audit.h"
32 #include <afs/afsutil.h>
34 /* --------------------------------
35 * interface & support code to manage text blocks within the
37 * --------------------------------
42 * routine mallocs storage for charListPtr, freed by stub
45 afs_int32 GetText(), GetTextVersion(), SaveText();
47 afs_int32 BUDB_GetText (call, lockHandle, textType, maxLength, offset,
48 nextOffset, charListPtr)
50 afs_uint32 lockHandle;
54 afs_int32 *nextOffset;
55 charListT *charListPtr;
59 code = GetText (call, lockHandle, textType, maxLength, offset,
60 nextOffset, charListPtr);
61 osi_auditU (call, BUDB_GetTxtEvent, code, AUD_LONG, textType, AUD_END);
65 afs_int32 GetText (call, lockHandle, textType, maxLength, offset,
66 nextOffset, charListPtr)
68 afs_uint32 lockHandle;
72 afs_int32 *nextOffset;
73 charListT *charListPtr;
75 struct ubik_trans *ut = 0;
77 afs_int32 transferSize, chunkSize;
78 afs_int32 blockOffset;
81 struct textBlock *tbPtr;
82 afs_int32 textRemaining;
86 LogDebug(5, "GetText: type %d, offset %d, nextOffset %d, maxLength %d\n",
87 textType, offset, nextOffset, maxLength);
89 if ( callPermitted(call) == 0 )
91 code = BUDB_NOTPERMITTED;
95 /* check parameters */
98 || (textType >= TB_NUM)
101 code = BUDB_BADARGUMENT;
105 /* start the transaction */
106 code = InitRPC(&ut, LOCKWRITE, 1);
110 /* fetch the lock state */
111 if ( checkLockHandle(ut, lockHandle) == 0)
113 code = BUDB_NOTLOCKED;
117 tbPtr = &db.h.textBlock[textType];
119 if ( (ntohl(tbPtr->size) > 0)
120 && (offset >= ntohl(tbPtr->size))
123 code = BUDB_BADARGUMENT;
127 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr->size));
129 /* compute minimum of remaining text or user buffer */
130 textRemaining = ntohl(tbPtr->size) - offset;
131 transferSize = MIN(textRemaining, maxLength);
133 /* allocate the transfer storage */
134 if (transferSize <= 0) {
135 charListPtr->charListT_len = 0L;
136 charListPtr->charListT_val = (char *)0;
139 charListPtr->charListT_len = transferSize;
140 charListPtr->charListT_val = (char *) malloc(transferSize);
141 if ( charListPtr->charListT_val == 0 )
145 textPtr = charListPtr->charListT_val;
146 *nextOffset = offset + transferSize;
148 /* setup the datablock. read and discard all blocks up to the one the
151 nblocks = offset/BLOCK_DATA_SIZE;
152 lastBlockAddr = ntohl(tbPtr->textAddr);
156 code = dbread(ut, lastBlockAddr, (char *) &block, sizeof(block));
159 lastBlockAddr = ntohl(block.h.next);
162 while ( transferSize > 0 )
164 code = dbread(ut, lastBlockAddr, (char *) &block, sizeof(block));
168 LogDebug(5, "fetched block %d\n", lastBlockAddr);
170 /* compute the data size to extract */
171 blockOffset = offset % BLOCK_DATA_SIZE;
172 textRemaining = BLOCK_DATA_SIZE - blockOffset;
173 chunkSize = min(textRemaining, transferSize);
175 memcpy(textPtr, &block.a[blockOffset], chunkSize);
177 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
179 transferSize -= chunkSize;
181 textPtr += chunkSize;
185 /* setup lastBlockAddr */
186 lastBlockAddr = ntohl(block.h.next);
190 if ( *nextOffset == ntohl(tbPtr->size) )
197 code = ubik_EndTrans(ut);
198 /* printf("in error exit, code=%ld\n", code); */
202 charListPtr->charListT_len = 0;
203 charListPtr->charListT_val = (char *) malloc(0);
208 /* printf("in abort exit, code=%ld\n", code); */
212 freeOldBlockChain(ut, diskAddr)
213 struct ubik_trans *ut;
216 struct blockHeader blockHeader;
220 while ( diskAddr != 0 )
222 /* read in the header */
223 code = dbread(ut, diskAddr, (char *) &blockHeader,sizeof(blockHeader));
226 nextDiskAddr = ntohl(blockHeader.next);
227 code = FreeBlock(ut, &blockHeader, diskAddr);
230 diskAddr = nextDiskAddr;
236 /* BUDB_GetTextVersion
237 * get the version number for the specified text block
240 afs_int32 BUDB_GetTextVersion (call, textType, tversion)
241 struct rx_call *call;
243 afs_uint32 *tversion;
247 code = GetTextVersion (call, textType, tversion);
248 osi_auditU (call, BUDB_GetTxVEvent, code, AUD_LONG, textType, AUD_END);
252 afs_int32 GetTextVersion (call, textType, tversion)
253 struct rx_call *call;
255 afs_uint32 *tversion;
258 struct ubik_trans *ut;
260 if ( callPermitted(call) == 0 )
261 return(BUDB_NOTPERMITTED);
263 if ( (textType < 0) || (textType >= TB_NUM) )
264 return(BUDB_BADARGUMENT);
266 code = InitRPC(&ut, LOCKREAD, 1);
270 *tversion = ntohl(db.h.textBlock[textType].version);
271 code = ubik_EndTrans(ut);
276 * next - next disk addr
277 * host/network ordering????
282 * charListPtr storage automatically malloced and freed
285 afs_int32 BUDB_SaveText (call, lockHandle, textType, offset, flags, charListPtr)
286 struct rx_call *call;
287 afs_uint32 lockHandle;
291 charListT *charListPtr;
295 code = SaveText (call, lockHandle, textType, offset, flags, charListPtr);
296 osi_auditU (call, BUDB_SavTxtEvent, code, AUD_LONG, textType, AUD_END);
300 afs_int32 SaveText (call, lockHandle, textType, offset, flags, charListPtr)
301 struct rx_call *call;
302 afs_uint32 lockHandle;
306 charListT *charListPtr;
308 struct ubik_trans *ut;
309 struct block diskBlock;
311 afs_int32 remainingInBlock, chunkSize;
312 struct textBlock *tbPtr;
313 afs_int32 textLength = charListPtr->charListT_len;
314 char *textptr = charListPtr->charListT_val;
317 LogDebug(5, "SaveText: type %d, offset %d, length %d\n",
318 textType, offset, textLength);
320 if ( callPermitted(call) == 0 )
321 return(BUDB_NOTPERMITTED);
323 if ( (textLength > BLOCK_DATA_SIZE) || (offset < 0) )
324 return(BUDB_BADARGUMENT);
326 code = InitRPC(&ut, LOCKWRITE, 1);
327 if (code) return(code);
329 /* fetch the lock state */
330 if ( checkLockHandle(ut, lockHandle) == 0)
331 ABORT(BUDB_NOTLOCKED);
333 if ( (textType < 0) || (textType >= TB_NUM) )
334 ABORT(BUDB_BADARGUMENT);
336 tbPtr = &db.h.textBlock[textType];
338 LogDebug(5, "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
339 lockHandle, textType, offset, flags, textLength);
343 /* release any blocks from previous transactions */
344 diskBlockAddr = ntohl(tbPtr->newTextAddr);
345 freeOldBlockChain(ut, diskBlockAddr);
349 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
350 if (code) ABORT(code);
352 LogDebug(5, "allocated block %d\n", diskBlockAddr);
355 diskBlock.h.type = text_BLOCK;
357 /* save it in the database header */
359 tbPtr->newTextAddr = htonl(diskBlockAddr);
360 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr, sizeof(struct textBlock));
365 tbPtr->newTextAddr = 0;
370 /* non-zero offset */
373 if (offset != ntohl(tbPtr->newsize))
374 ABORT(BUDB_BADARGUMENT);
376 /* locate the block to which offset refers */
377 nblocks = offset/BLOCK_DATA_SIZE;
379 diskBlockAddr = ntohl(tbPtr->newTextAddr);
380 if (diskBlockAddr == 0)
381 ABORT(BUDB_BADARGUMENT);
383 code = dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
384 if (code) ABORT(code);
388 diskBlockAddr = ntohl(diskBlock.h.next);
389 code = dbread(ut, diskBlockAddr, (char *) &diskBlock, sizeof(diskBlock));
390 if (code) ABORT(code);
394 /* diskBlock and diskBlockAddr now point to the last block in the chain */
398 /* compute the transfer size */
399 remainingInBlock = (BLOCK_DATA_SIZE - (offset % BLOCK_DATA_SIZE));
400 chunkSize = MIN(remainingInBlock, textLength);
402 /* copy in the data */
403 memcpy(&diskBlock.a[offset % BLOCK_DATA_SIZE], textptr, chunkSize);
405 /* LogDebug(5, "text is %s\n", textptr); */
407 textLength -= chunkSize;
408 textptr += chunkSize;
410 tbPtr->newsize = htonl(ntohl(tbPtr->newsize) + chunkSize);
412 if ( textLength > 0 )
414 afs_int32 prevBlockAddr;
415 afs_int32 linkOffset;
418 /* have to add another block to the chain */
420 code = dbwrite(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
421 if (code) ABORT(code);
423 prevBlockAddr = (afs_int32) diskBlockAddr;
424 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
425 if (code) ABORT(code);
427 LogDebug(5, "allocated block %d\n", diskBlockAddr);
430 diskBlock.h.type = text_BLOCK;
432 /* now have to update the previous block's link */
433 linkOffset = (afs_int32) &diskBlock.h.next - (afs_int32) &diskBlock;
434 linkValue = htonl(diskBlockAddr);
436 code = dbwrite(ut, (afs_int32)prevBlockAddr + linkOffset, (char *)&linkValue, sizeof(afs_int32));
437 if (code) ABORT(code);
441 /* just write the old block */
442 code = dbwrite(ut, diskBlockAddr, (char *) &diskBlock, sizeof(diskBlock));
443 if (code) ABORT(code);
447 if ( flags & BUDB_TEXT_COMPLETE ) /* done */
449 /* this was the last chunk of text */
450 diskBlockAddr = ntohl(tbPtr->textAddr);
451 freeOldBlockChain(ut, diskBlockAddr);
453 tbPtr->textAddr = tbPtr->newTextAddr;
454 tbPtr->newTextAddr = 0;
455 tbPtr->size = tbPtr->newsize;
457 tbPtr->version = htonl(ntohl(tbPtr->version) + 1);
459 /* saveTextToFile(ut, tbPtr); */
462 /* update size and other text header info */
463 code = dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr, sizeof(struct textBlock));
464 if (code) ABORT(code);
467 code = ubik_EndTrans(ut);
477 saveTextToFile(ut, tbPtr)
478 struct ubik_trans *ut;
479 struct textBlock *tbPtr;
485 afs_int32 size, chunkSize;
488 sprintf(filename, "%s/%s", gettmpdir(), "dbg_XXXXXX");
490 fid = mkstemp(filename);
491 size = ntohl(tbPtr->size);
492 blockAddr = ntohl(tbPtr->textAddr);
495 chunkSize = MIN(BLOCK_DATA_SIZE, size);
496 dbread(ut, blockAddr, (char *) &block, sizeof(block));
497 write(fid, &block.a[0], chunkSize);
498 blockAddr = ntohl(block.h.next);
502 printf("wrote debug file %s\n", filename);
506 #if (defined(AFS_DEC_ENV) || defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
510 * st - string containing template for a tmp file name
513 * 0-n - open file descriptor
515 * 1) missing in Ultrix, HP/UX and AIX 221 environment
516 * 2) iterate some number of times to alleviate the race?
525 #ifdef AFS_LINUX20_ENV
526 retval = open(mkstemp(st), O_RDWR|O_CREAT|O_EXCL, 0600);
528 retval = open(mktemp(st), O_RDWR|O_CREAT|O_EXCL, 0600);