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 "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(), GetTextVersion(), SaveText();
49 SBUDB_GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
52 afs_uint32 lockHandle;
56 afs_int32 *nextOffset;
57 charListT *charListPtr;
62 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
64 osi_auditU(call, BUDB_GetTxtEvent, code, AUD_LONG, textType, AUD_END);
69 GetText(call, lockHandle, textType, maxLength, offset, nextOffset,
72 afs_uint32 lockHandle;
76 afs_int32 *nextOffset;
77 charListT *charListPtr;
79 struct ubik_trans *ut = 0;
81 afs_int32 transferSize, chunkSize;
82 afs_int32 blockOffset;
85 struct textBlock *tbPtr;
86 afs_int32 textRemaining;
90 LogDebug(5, "GetText: type %d, offset %d, nextOffset %d, maxLength %d\n",
91 textType, offset, nextOffset, maxLength);
93 if (callPermitted(call) == 0) {
94 code = BUDB_NOTPERMITTED;
98 /* check parameters */
101 || (textType >= TB_NUM)
103 code = BUDB_BADARGUMENT;
107 /* start the transaction */
108 code = InitRPC(&ut, LOCKWRITE, 1);
112 /* fetch the lock state */
113 if (checkLockHandle(ut, lockHandle) == 0) {
114 code = BUDB_NOTLOCKED;
118 tbPtr = &db.h.textBlock[textType];
120 if ((ntohl(tbPtr->size) > 0)
121 && (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 = NULL;
138 charListPtr->charListT_len = transferSize;
139 charListPtr->charListT_val = (char *)malloc(transferSize);
140 if (charListPtr->charListT_val == 0)
144 textPtr = charListPtr->charListT_val;
145 *nextOffset = offset + transferSize;
147 /* setup the datablock. read and discard all blocks up to the one the
150 nblocks = offset / BLOCK_DATA_SIZE;
151 lastBlockAddr = ntohl(tbPtr->textAddr);
154 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
157 lastBlockAddr = ntohl(block.h.next);
160 while (transferSize > 0) {
161 code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block));
165 LogDebug(5, "fetched block %d\n", lastBlockAddr);
167 /* compute the data size to extract */
168 blockOffset = offset % BLOCK_DATA_SIZE;
169 textRemaining = BLOCK_DATA_SIZE - blockOffset;
170 chunkSize = min(textRemaining, transferSize);
172 memcpy(textPtr, &block.a[blockOffset], chunkSize);
174 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
176 transferSize -= chunkSize;
178 textPtr += chunkSize;
181 /* setup lastBlockAddr */
182 lastBlockAddr = ntohl(block.h.next);
186 if (*nextOffset == ntohl(tbPtr->size)) {
192 code = ubik_EndTrans(ut);
193 /* printf("in error exit, code=%ld\n", code); */
197 charListPtr->charListT_len = 0;
198 charListPtr->charListT_val = (char *)malloc(0);
203 /* printf("in abort exit, code=%ld\n", code); */
207 freeOldBlockChain(ut, diskAddr)
208 struct ubik_trans *ut;
211 struct blockHeader blockHeader;
215 while (diskAddr != 0) {
216 /* read in the header */
218 dbread(ut, diskAddr, (char *)&blockHeader, sizeof(blockHeader));
221 nextDiskAddr = ntohl(blockHeader.next);
222 code = FreeBlock(ut, &blockHeader, diskAddr);
225 diskAddr = nextDiskAddr;
231 /* BUDB_GetTextVersion
232 * get the version number for the specified text block
236 SBUDB_GetTextVersion(call, textType, tversion)
237 struct rx_call *call;
239 afs_uint32 *tversion;
243 code = GetTextVersion(call, textType, tversion);
244 osi_auditU(call, BUDB_GetTxVEvent, code, AUD_LONG, textType, AUD_END);
249 GetTextVersion(call, textType, tversion)
250 struct rx_call *call;
252 afs_uint32 *tversion;
255 struct ubik_trans *ut;
257 if (callPermitted(call) == 0)
258 return (BUDB_NOTPERMITTED);
260 if ((textType < 0) || (textType >= TB_NUM))
261 return (BUDB_BADARGUMENT);
263 code = InitRPC(&ut, LOCKREAD, 1);
267 *tversion = ntohl(db.h.textBlock[textType].version);
268 code = ubik_EndTrans(ut);
273 * next - next disk addr
274 * host/network ordering????
279 * charListPtr storage automatically malloced and freed
283 SBUDB_SaveText(call, lockHandle, textType, offset, flags, charListPtr)
284 struct rx_call *call;
285 afs_uint32 lockHandle;
289 charListT *charListPtr;
293 code = SaveText(call, lockHandle, textType, offset, flags, charListPtr);
294 osi_auditU(call, BUDB_SavTxtEvent, code, AUD_LONG, textType, AUD_END);
299 SaveText(call, lockHandle, textType, offset, flags, charListPtr)
300 struct rx_call *call;
301 afs_uint32 lockHandle;
305 charListT *charListPtr;
307 struct ubik_trans *ut;
308 struct block diskBlock;
310 afs_int32 remainingInBlock, chunkSize;
311 struct textBlock *tbPtr;
312 afs_int32 textLength = charListPtr->charListT_len;
313 char *textptr = charListPtr->charListT_val;
316 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType, offset,
319 if (callPermitted(call) == 0)
320 return (BUDB_NOTPERMITTED);
322 if ((textLength > BLOCK_DATA_SIZE) || (offset < 0))
323 return (BUDB_BADARGUMENT);
325 code = InitRPC(&ut, LOCKWRITE, 1);
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];
339 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
340 lockHandle, textType, offset, flags, textLength);
343 /* release any blocks from previous transactions */
344 diskBlockAddr = ntohl(tbPtr->newTextAddr);
345 freeOldBlockChain(ut, diskBlockAddr);
348 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
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,
361 sizeof(struct textBlock));
364 tbPtr->newTextAddr = 0;
367 /* non-zero offset */
370 if (offset != ntohl(tbPtr->newsize))
371 ABORT(BUDB_BADARGUMENT);
373 /* locate the block to which offset refers */
374 nblocks = offset / BLOCK_DATA_SIZE;
376 diskBlockAddr = ntohl(tbPtr->newTextAddr);
377 if (diskBlockAddr == 0)
378 ABORT(BUDB_BADARGUMENT);
381 dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock));
386 diskBlockAddr = ntohl(diskBlock.h.next);
388 dbread(ut, diskBlockAddr, (char *)&diskBlock,
395 /* 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) {
413 afs_int32 prevBlockAddr;
414 afs_int32 linkOffset;
417 /* have to add another block to the chain */
420 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
425 prevBlockAddr = (afs_int32) diskBlockAddr;
426 code = AllocBlock(ut, &diskBlock, &diskBlockAddr);
430 LogDebug(5, "allocated block %d\n", diskBlockAddr);
433 diskBlock.h.type = text_BLOCK;
435 /* now have to update the previous block's link */
437 (afs_int32) ((char*)& diskBlock.h.next - (char*)& diskBlock);
438 linkValue = htonl(diskBlockAddr);
441 dbwrite(ut, (afs_int32) prevBlockAddr + linkOffset,
442 (char *)&linkValue, sizeof(afs_int32));
446 /* just write the old block */
448 dbwrite(ut, diskBlockAddr, (char *)&diskBlock,
455 if (flags & BUDB_TEXT_COMPLETE) { /* done */
456 /* this was the last chunk of text */
457 diskBlockAddr = ntohl(tbPtr->textAddr);
458 freeOldBlockChain(ut, diskBlockAddr);
460 tbPtr->textAddr = tbPtr->newTextAddr;
461 tbPtr->newTextAddr = 0;
462 tbPtr->size = tbPtr->newsize;
464 tbPtr->version = htonl(ntohl(tbPtr->version) + 1);
466 /* saveTextToFile(ut, tbPtr); */
469 /* update size and other text header info */
471 dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr,
472 sizeof(struct textBlock));
477 code = ubik_EndTrans(ut);
487 saveTextToFile(ut, tbPtr)
488 struct ubik_trans *ut;
489 struct textBlock *tbPtr;
495 afs_int32 size, chunkSize;
498 sprintf(filename, "%s/%s", gettmpdir(), "dbg_XXXXXX");
500 fid = mkstemp(filename);
501 size = ntohl(tbPtr->size);
502 blockAddr = ntohl(tbPtr->textAddr);
504 chunkSize = MIN(BLOCK_DATA_SIZE, size);
505 dbread(ut, blockAddr, (char *)&block, sizeof(block));
506 write(fid, &block.a[0], chunkSize);
507 blockAddr = ntohl(block.h.next);
511 printf("wrote debug file %s\n", filename);
515 #if (defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
519 * st - string containing template for a tmp file name
522 * 0-n - open file descriptor
524 * 1) missing in Ultrix, HP/UX and AIX 221 environment
525 * 2) iterate some number of times to alleviate the race?
534 #ifdef AFS_LINUX20_ENV
535 retval = open(mkstemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);
537 retval = open(mktemp(st), O_RDWR | O_CREAT | O_EXCL, 0600);