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>
34 #include <afs/bubasics.h>
35 #include "budb_errs.h"
37 #include "error_macros.h"
38 #include "afs/audit.h"
39 #include <afs/afsutil.h>
41 /* --------------------------------
42 * interface & support code to manage text blocks within the
44 * --------------------------------
49 * routine mallocs storage for charListPtr, freed by stub
52 afs_int32 GetText(), GetTextVersion(), SaveText();
55 SBUDB_GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
58 afs_uint32 lockHandle;
62 afs_int32 *nextOffset;
63 charListT *charListPtr;
68 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
70 osi_auditU(call, BUDB_GetTxtEvent, code, AUD_LONG, textType, AUD_END);
75 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
78 afs_uint32 lockHandle;
82 afs_int32 *nextOffset;
83 charListT *charListPtr;
85 struct ubik_trans *ut = 0;
87 afs_int32 transferSize, chunkSize;
88 afs_int32 blockOffset;
91 struct textBlock *tbPtr;
92 afs_int32 textRemaining;
96 LogDebug(5, "GetText: type %d, offset %d, nextOffset %d, maxLength %d\n",
97 textType, offset, nextOffset, maxLength);
99 if (callPermitted(call) == 0) {
100 code = BUDB_NOTPERMITTED;
104 /* check parameters */
107 || (textType >= TB_NUM)
109 code = BUDB_BADARGUMENT;
113 /* start the transaction */
114 code = InitRPC(&ut, LOCKWRITE, 1);
118 /* fetch the lock state */
119 if (checkLockHandle(ut, lockHandle) == 0) {
120 code = BUDB_NOTLOCKED;
124 tbPtr = &db.h.textBlock[textType];
126 if ((ntohl(tbPtr->size) > 0)
127 && (offset >= ntohl(tbPtr->size))
129 code = BUDB_BADARGUMENT;
133 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr->size));
135 /* compute minimum of remaining text or user buffer */
136 textRemaining = ntohl(tbPtr->size) - offset;
137 transferSize = MIN(textRemaining, maxLength);
139 /* allocate the transfer storage */
140 if (transferSize <= 0) {
141 charListPtr->charListT_len = 0L;
142 charListPtr->charListT_val = NULL;
144 charListPtr->charListT_len = transferSize;
145 charListPtr->charListT_val = (char *)malloc(transferSize);
146 if (charListPtr->charListT_val == 0)
150 textPtr = charListPtr->charListT_val;
151 *nextOffset = offset + transferSize;
153 /* setup the datablock. read and discard all blocks up to the one the
156 nblocks = offset / BLOCK_DATA_SIZE;
157 lastBlockAddr = ntohl(tbPtr->textAddr);
160 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
163 lastBlockAddr = ntohl(block.h.next);
166 while (transferSize > 0) {
167 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
171 LogDebug(5, "fetched block %d\n", lastBlockAddr);
173 /* compute the data size to extract */
174 blockOffset = offset % BLOCK_DATA_SIZE;
175 textRemaining = BLOCK_DATA_SIZE - blockOffset;
176 chunkSize = min(textRemaining, transferSize);
178 memcpy(textPtr, &block.a[blockOffset], chunkSize);
180 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
182 transferSize -= chunkSize;
184 textPtr += chunkSize;
187 /* setup lastBlockAddr */
188 lastBlockAddr = ntohl(block.h.next);
192 if (*nextOffset == ntohl(tbPtr->size)) {
198 code = ubik_EndTrans(ut);
199 /* printf("in error exit, code=%ld\n", code); */
203 charListPtr->charListT_len = 0;
204 charListPtr->charListT_val = (char *)malloc(0);
209 /* printf("in abort exit, code=%ld\n", code); */
213 freeOldBlockChain(ut, diskAddr)
214 struct ubik_trans *ut;
217 struct blockHeader blockHeader;
221 while (diskAddr != 0) {
222 /* read in the header */
224 dbread(ut, diskAddr, (char *)&blockHeader, sizeof(blockHeader));
227 nextDiskAddr = ntohl(blockHeader.next);
228 code = FreeBlock(ut, &blockHeader, diskAddr);
231 diskAddr = nextDiskAddr;
237 /* BUDB_GetTextVersion
238 * get the version number for the specified text block
242 SBUDB_GetTextVersion(call, textType, tversion)
243 struct rx_call *call;
245 afs_uint32 *tversion;
249 code = GetTextVersion(call, textType, tversion);
250 osi_auditU(call, BUDB_GetTxVEvent, code, AUD_LONG, textType, AUD_END);
255 GetTextVersion(call, textType, tversion)
256 struct rx_call *call;
258 afs_uint32 *tversion;
261 struct ubik_trans *ut;
263 if (callPermitted(call) == 0)
264 return (BUDB_NOTPERMITTED);
266 if ((textType < 0) || (textType >= TB_NUM))
267 return (BUDB_BADARGUMENT);
269 code = InitRPC(&ut, LOCKREAD, 1);
273 *tversion = ntohl(db.h.textBlock[textType].version);
274 code = ubik_EndTrans(ut);
279 * next - next disk addr
280 * host/network ordering????
285 * charListPtr storage automatically malloced and freed
289 SBUDB_SaveText(call, lockHandle, textType, offset, flags, charListPtr)
290 struct rx_call *call;
291 afs_uint32 lockHandle;
295 charListT *charListPtr;
299 code = SaveText(call, lockHandle, textType, offset, flags, charListPtr);
300 osi_auditU(call, BUDB_SavTxtEvent, code, AUD_LONG, textType, AUD_END);
305 SaveText(call, lockHandle, textType, offset, flags, charListPtr)
306 struct rx_call *call;
307 afs_uint32 lockHandle;
311 charListT *charListPtr;
313 struct ubik_trans *ut;
314 struct block diskBlock;
316 afs_int32 remainingInBlock, chunkSize;
317 struct textBlock *tbPtr;
318 afs_int32 textLength = charListPtr->charListT_len;
319 char *textptr = charListPtr->charListT_val;
322 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType, offset,
325 if (callPermitted(call) == 0)
326 return (BUDB_NOTPERMITTED);
328 if ((textLength > BLOCK_DATA_SIZE) || (offset < 0))
329 return (BUDB_BADARGUMENT);
331 code = InitRPC(&ut, LOCKWRITE, 1);
335 /* fetch the lock state */
336 if (checkLockHandle(ut, lockHandle) == 0)
337 ABORT(BUDB_NOTLOCKED);
339 if ((textType < 0) || (textType >= TB_NUM))
340 ABORT(BUDB_BADARGUMENT);
342 tbPtr = &db.h.textBlock[textType];
345 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
346 lockHandle, textType, offset, flags, textLength);
349 /* release any blocks from previous transactions */
350 diskBlockAddr = ntohl(tbPtr->newTextAddr);
351 freeOldBlockChain(ut, diskBlockAddr);
354 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
358 LogDebug(5, "allocated block %d\n", diskBlockAddr);
361 diskBlock.h.type = text_BLOCK;
363 /* save it in the database header */
365 tbPtr->newTextAddr = htonl(diskBlockAddr);
366 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
367 sizeof(struct textBlock));
370 tbPtr->newTextAddr = 0;
373 /* non-zero offset */
376 if (offset != ntohl(tbPtr->newsize))
377 ABORT(BUDB_BADARGUMENT);
379 /* locate the block to which offset refers */
380 nblocks = offset / BLOCK_DATA_SIZE;
382 diskBlockAddr = ntohl(tbPtr->newTextAddr);
383 if (diskBlockAddr == 0)
384 ABORT(BUDB_BADARGUMENT);
387 dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
392 diskBlockAddr = ntohl(diskBlock.h.next);
394 dbread(ut, diskBlockAddr, (char *)&diskBlock,
401 /* diskBlock and diskBlockAddr now point to the last block in the chain */
404 /* compute the transfer size */
405 remainingInBlock = (BLOCK_DATA_SIZE - (offset % BLOCK_DATA_SIZE));
406 chunkSize = MIN(remainingInBlock, textLength);
408 /* copy in the data */
409 memcpy(&diskBlock.a[offset % BLOCK_DATA_SIZE], textptr, chunkSize);
411 /* LogDebug(5, "text is %s\n", textptr); */
413 textLength -= chunkSize;
414 textptr += chunkSize;
416 tbPtr->newsize = htonl(ntohl(tbPtr->newsize) + chunkSize);
418 if (textLength > 0) {
419 afs_int32 prevBlockAddr;
420 afs_int32 linkOffset;
423 /* have to add another block to the chain */
426 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
431 prevBlockAddr = (afs_int32) diskBlockAddr;
432 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
436 LogDebug(5, "allocated block %d\n", diskBlockAddr);
439 diskBlock.h.type = text_BLOCK;
441 /* now have to update the previous block's link */
443 (afs_int32) ((char*)& diskBlock.h.next - (char*)& diskBlock);
444 linkValue = htonl(diskBlockAddr);
447 dbwrite(ut, (afs_int32) prevBlockAddr + linkOffset,
448 (char *)&linkValue, sizeof(afs_int32));
452 /* just write the old block */
454 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
461 if (flags & BUDB_TEXT_COMPLETE) { /* done */
462 /* this was the last chunk of text */
463 diskBlockAddr = ntohl(tbPtr->textAddr);
464 freeOldBlockChain(ut, diskBlockAddr);
466 tbPtr->textAddr = tbPtr->newTextAddr;
467 tbPtr->newTextAddr = 0;
468 tbPtr->size = tbPtr->newsize;
470 tbPtr->version = htonl(ntohl(tbPtr->version) + 1);
472 /* saveTextToFile(ut, tbPtr); */
475 /* update size and other text header info */
477 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
478 sizeof(struct textBlock));
483 code = ubik_EndTrans(ut);
493 saveTextToFile(ut, tbPtr)
494 struct ubik_trans *ut;
495 struct textBlock *tbPtr;
501 afs_int32 size, chunkSize;
504 sprintf(filename, "%s/%s", gettmpdir(), "dbg_XXXXXX");
506 fid = mkstemp(filename);
507 size = ntohl(tbPtr->size);
508 blockAddr = ntohl(tbPtr->textAddr);
510 chunkSize = MIN(BLOCK_DATA_SIZE, size);
511 dbread(ut, blockAddr, (char *)&block, sizeof(block));
512 write(fid, &block.a[0], chunkSize);
513 blockAddr = ntohl(block.h.next);
517 printf("wrote debug file %s\n", filename);
521 #if (defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
525 * st - string containing template for a tmp file name
528 * 0-n - open file descriptor
530 * 1) missing in Ultrix, HP/UX and AIX 221 environment
531 * 2) iterate some number of times to alleviate the race?
540 #ifdef AFS_LINUX20_ENV
541 retval = open(mkstemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);
543 retval = open(mktemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);