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>
19 #include <netinet/in.h>
21 #include <sys/param.h>
24 #include <sys/types.h>
26 #include <afs/bubasics.h>
27 #include "budb_errs.h"
29 #include "error_macros.h"
30 #include "budb_internal.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(struct rx_call
*, afs_uint32
, afs_int32
, afs_int32
,
46 afs_int32
, afs_int32
*, charListT
*);
47 afs_int32
GetTextVersion(struct rx_call
*, afs_int32
, afs_uint32
*);
48 afs_int32
SaveText(struct rx_call
*, afs_uint32
, afs_int32
, afs_int32
,
49 afs_int32
, charListT
*);
52 SBUDB_GetText(struct rx_call
*call
, afs_uint32 lockHandle
, afs_int32 textType
,
53 afs_int32 maxLength
, afs_int32 offset
, afs_int32
*nextOffset
,
54 charListT
*charListPtr
)
59 GetText(call
, lockHandle
, textType
, maxLength
, offset
, nextOffset
,
61 osi_auditU(call
, BUDB_GetTxtEvent
, code
, AUD_LONG
, textType
, AUD_END
);
66 GetText(struct rx_call
*call
, afs_uint32 lockHandle
, afs_int32 textType
,
67 afs_int32 maxLength
, afs_int32 offset
, afs_int32
*nextOffset
,
68 charListT
*charListPtr
)
70 struct ubik_trans
*ut
= 0;
72 afs_int32 transferSize
, chunkSize
;
73 afs_int32 blockOffset
;
76 struct textBlock
*tbPtr
;
77 afs_int32 textRemaining
;
81 LogDebug(5, "GetText: type %d, offset %d, nextOffset %"AFS_PTR_FMT
82 ", maxLength %d\n", textType
, offset
, nextOffset
, maxLength
);
84 if (callPermitted(call
) == 0) {
85 code
= BUDB_NOTPERMITTED
;
89 /* check parameters */
92 || (textType
>= TB_NUM
)
94 code
= BUDB_BADARGUMENT
;
98 /* start the transaction */
99 code
= InitRPC(&ut
, LOCKWRITE
, 1);
103 /* fetch the lock state */
104 if (checkLockHandle(ut
, lockHandle
) == 0) {
105 code
= BUDB_NOTLOCKED
;
109 tbPtr
= &db
.h
.textBlock
[textType
];
111 if ((ntohl(tbPtr
->size
) > 0)
112 && (offset
>= ntohl(tbPtr
->size
))
114 code
= BUDB_BADARGUMENT
;
118 LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr
->size
));
120 /* compute minimum of remaining text or user buffer */
121 textRemaining
= ntohl(tbPtr
->size
) - offset
;
122 transferSize
= MIN(textRemaining
, maxLength
);
124 /* allocate the transfer storage */
125 if (transferSize
<= 0) {
126 charListPtr
->charListT_len
= 0L;
127 charListPtr
->charListT_val
= NULL
;
129 charListPtr
->charListT_len
= transferSize
;
130 charListPtr
->charListT_val
= (char *)malloc(transferSize
);
131 if (charListPtr
->charListT_val
== 0)
135 textPtr
= charListPtr
->charListT_val
;
136 *nextOffset
= offset
+ transferSize
;
138 /* setup the datablock. read and discard all blocks up to the one the
141 nblocks
= offset
/ BLOCK_DATA_SIZE
;
142 lastBlockAddr
= ntohl(tbPtr
->textAddr
);
145 code
= dbread(ut
, lastBlockAddr
, (char *)&block
, sizeof(block
));
148 lastBlockAddr
= ntohl(block
.h
.next
);
151 while (transferSize
> 0) {
152 code
= dbread(ut
, lastBlockAddr
, (char *)&block
, sizeof(block
));
156 LogDebug(5, "fetched block %d\n", lastBlockAddr
);
158 /* compute the data size to extract */
159 blockOffset
= offset
% BLOCK_DATA_SIZE
;
160 textRemaining
= BLOCK_DATA_SIZE
- blockOffset
;
161 chunkSize
= min(textRemaining
, transferSize
);
163 memcpy(textPtr
, &block
.a
[blockOffset
], chunkSize
);
165 /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */
167 transferSize
-= chunkSize
;
169 textPtr
+= chunkSize
;
172 /* setup lastBlockAddr */
173 lastBlockAddr
= ntohl(block
.h
.next
);
177 if (*nextOffset
== ntohl(tbPtr
->size
)) {
183 code
= ubik_EndTrans(ut
);
184 /* printf("in error exit, code=%ld\n", code); */
188 charListPtr
->charListT_len
= 0;
189 charListPtr
->charListT_val
= (char *)malloc(0);
194 /* printf("in abort exit, code=%ld\n", code); */
199 freeOldBlockChain(struct ubik_trans
*ut
, dbadr diskAddr
)
201 struct blockHeader blockHeader
;
205 while (diskAddr
!= 0) {
206 /* read in the header */
208 dbread(ut
, diskAddr
, (char *)&blockHeader
, sizeof(blockHeader
));
211 nextDiskAddr
= ntohl(blockHeader
.next
);
212 code
= FreeBlock(ut
, &blockHeader
, diskAddr
);
215 diskAddr
= nextDiskAddr
;
221 /* BUDB_GetTextVersion
222 * get the version number for the specified text block
226 SBUDB_GetTextVersion(struct rx_call
*call
, afs_int32 textType
,
227 afs_uint32
*tversion
)
231 code
= GetTextVersion(call
, textType
, tversion
);
232 osi_auditU(call
, BUDB_GetTxVEvent
, code
, AUD_LONG
, textType
, AUD_END
);
237 GetTextVersion(struct rx_call
*call
, afs_int32 textType
,
238 afs_uint32
*tversion
)
241 struct ubik_trans
*ut
;
243 if (callPermitted(call
) == 0)
244 return (BUDB_NOTPERMITTED
);
246 if ((textType
< 0) || (textType
>= TB_NUM
))
247 return (BUDB_BADARGUMENT
);
249 code
= InitRPC(&ut
, LOCKREAD
, 1);
253 *tversion
= ntohl(db
.h
.textBlock
[textType
].version
);
254 code
= ubik_EndTrans(ut
);
259 * next - next disk addr
260 * host/network ordering????
265 * charListPtr storage automatically malloced and freed
269 SBUDB_SaveText(struct rx_call
*call
, afs_uint32 lockHandle
,
270 afs_int32 textType
, afs_int32 offset
, afs_int32 flags
,
271 charListT
*charListPtr
)
275 code
= SaveText(call
, lockHandle
, textType
, offset
, flags
, charListPtr
);
276 osi_auditU(call
, BUDB_SavTxtEvent
, code
, AUD_LONG
, textType
, AUD_END
);
281 SaveText(struct rx_call
*call
, afs_uint32 lockHandle
, afs_int32 textType
,
282 afs_int32 offset
, afs_int32 flags
, charListT
*charListPtr
)
284 struct ubik_trans
*ut
;
285 struct block diskBlock
;
287 afs_int32 remainingInBlock
, chunkSize
;
288 struct textBlock
*tbPtr
;
289 afs_int32 textLength
= charListPtr
->charListT_len
;
290 char *textptr
= charListPtr
->charListT_val
;
293 LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType
, offset
,
296 if (callPermitted(call
) == 0)
297 return (BUDB_NOTPERMITTED
);
299 if ((textLength
> BLOCK_DATA_SIZE
) || (offset
< 0))
300 return (BUDB_BADARGUMENT
);
302 code
= InitRPC(&ut
, LOCKWRITE
, 1);
306 /* fetch the lock state */
307 if (checkLockHandle(ut
, lockHandle
) == 0)
308 ABORT(BUDB_NOTLOCKED
);
310 if ((textType
< 0) || (textType
>= TB_NUM
))
311 ABORT(BUDB_BADARGUMENT
);
313 tbPtr
= &db
.h
.textBlock
[textType
];
316 "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n",
317 lockHandle
, textType
, offset
, flags
, textLength
);
320 /* release any blocks from previous transactions */
321 diskBlockAddr
= ntohl(tbPtr
->newTextAddr
);
322 freeOldBlockChain(ut
, diskBlockAddr
);
325 code
= AllocBlock(ut
, &diskBlock
, &diskBlockAddr
);
329 LogDebug(5, "allocated block %d\n", diskBlockAddr
);
332 diskBlock
.h
.type
= text_BLOCK
;
334 /* save it in the database header */
336 tbPtr
->newTextAddr
= htonl(diskBlockAddr
);
337 dbwrite(ut
, (char *)tbPtr
- (char *)&db
.h
, (char *)tbPtr
,
338 sizeof(struct textBlock
));
341 tbPtr
->newTextAddr
= 0;
344 /* non-zero offset */
347 if (offset
!= ntohl(tbPtr
->newsize
))
348 ABORT(BUDB_BADARGUMENT
);
350 /* locate the block to which offset refers */
351 nblocks
= offset
/ BLOCK_DATA_SIZE
;
353 diskBlockAddr
= ntohl(tbPtr
->newTextAddr
);
354 if (diskBlockAddr
== 0)
355 ABORT(BUDB_BADARGUMENT
);
358 dbread(ut
, diskBlockAddr
, (char *)&diskBlock
, sizeof(diskBlock
));
363 diskBlockAddr
= ntohl(diskBlock
.h
.next
);
365 dbread(ut
, diskBlockAddr
, (char *)&diskBlock
,
372 /* diskBlock and diskBlockAddr now point to the last block in the chain */
375 /* compute the transfer size */
376 remainingInBlock
= (BLOCK_DATA_SIZE
- (offset
% BLOCK_DATA_SIZE
));
377 chunkSize
= MIN(remainingInBlock
, textLength
);
379 /* copy in the data */
380 memcpy(&diskBlock
.a
[offset
% BLOCK_DATA_SIZE
], textptr
, chunkSize
);
382 /* LogDebug(5, "text is %s\n", textptr); */
384 textLength
-= chunkSize
;
385 textptr
+= chunkSize
;
387 tbPtr
->newsize
= htonl(ntohl(tbPtr
->newsize
) + chunkSize
);
389 if (textLength
> 0) {
390 afs_int32 prevBlockAddr
;
391 afs_int32 linkOffset
;
394 /* have to add another block to the chain */
397 dbwrite(ut
, diskBlockAddr
, (char *)&diskBlock
,
402 prevBlockAddr
= (afs_int32
) diskBlockAddr
;
403 code
= AllocBlock(ut
, &diskBlock
, &diskBlockAddr
);
407 LogDebug(5, "allocated block %d\n", diskBlockAddr
);
410 diskBlock
.h
.type
= text_BLOCK
;
412 /* now have to update the previous block's link */
414 (afs_int32
) ((char*)& diskBlock
.h
.next
- (char*)& diskBlock
);
415 linkValue
= htonl(diskBlockAddr
);
418 dbwrite(ut
, (afs_int32
) prevBlockAddr
+ linkOffset
,
419 (char *)&linkValue
, sizeof(afs_int32
));
423 /* just write the old block */
425 dbwrite(ut
, diskBlockAddr
, (char *)&diskBlock
,
432 if (flags
& BUDB_TEXT_COMPLETE
) { /* done */
433 /* this was the last chunk of text */
434 diskBlockAddr
= ntohl(tbPtr
->textAddr
);
435 freeOldBlockChain(ut
, diskBlockAddr
);
437 tbPtr
->textAddr
= tbPtr
->newTextAddr
;
438 tbPtr
->newTextAddr
= 0;
439 tbPtr
->size
= tbPtr
->newsize
;
441 tbPtr
->version
= htonl(ntohl(tbPtr
->version
) + 1);
443 /* saveTextToFile(ut, tbPtr); */
446 /* update size and other text header info */
448 dbwrite(ut
, (char *)tbPtr
- (char *)&db
.h
, (char *)tbPtr
,
449 sizeof(struct textBlock
));
454 code
= ubik_EndTrans(ut
);
464 saveTextToFile(struct ubik_trans
*ut
, struct textBlock
*tbPtr
)
469 afs_int32 size
, totalSize
, chunkSize
;
472 sprintf(filename
, "%s/%s", gettmpdir(), "dbg_XXXXXX");
474 fid
= mkstemp(filename
);
475 totalSize
= size
= ntohl(tbPtr
->size
);
476 blockAddr
= ntohl(tbPtr
->textAddr
);
478 chunkSize
= MIN(BLOCK_DATA_SIZE
, size
);
479 dbread(ut
, blockAddr
, (char *)&block
, sizeof(block
));
480 if (write(fid
, &block
.a
[0], chunkSize
) < 0)
482 blockAddr
= ntohl(block
.h
.next
);
487 printf("Wrote partial debug file (%ld bytes out of %ld)\n",
488 (long)(totalSize
- size
), (long)totalSize
);
490 printf("wrote debug file %s\n", filename
);
495 #if (defined(AFS_HPUX_ENV)) || defined(AFS_NT40_ENV)
499 * st - string containing template for a tmp file name
502 * 0-n - open file descriptor
504 * 1) missing in Ultrix, HP/UX and AIX 221 environment
505 * 2) iterate some number of times to alleviate the race?
513 #ifdef AFS_LINUX20_ENV
514 retval
= open(mkstemp(st
), O_RDWR
| O_CREAT
| O_EXCL
, 0600);
516 retval
= open(mktemp(st
), O_RDWR
| O_CREAT
| O_EXCL
, 0600);