afs_int32 FreeAllLocks(struct rx_call *call, afs_uint32 instanceId) { db_lockP startPtr, endPtr; struct ubik_trans *ut; afs_int32 code; if (callPermitted(call) == 0) return (BUDB_NOTPERMITTED); code = InitRPC(&ut, LOCKWRITE, 1); if (code) return (code); startPtr = &db.h.textLocks[0]; endPtr = &db.h.textLocks[TB_NUM - 1]; while (startPtr <= endPtr) { if ((ntohl(startPtr->lockState) == 1) && (ntohl(startPtr->instanceId) == instanceId) ) { /* release the lock */ startPtr->lockState = 0; /* unlock it */ startPtr->lockTime = 0; startPtr->expires = 0; startPtr->instanceId = 0; dbwrite(ut, DBH_POS(startPtr), (char *)startPtr, sizeof(db_lockT)); } startPtr++; } code = ubik_EndTrans(ut); return (code); }
void * setupDbDump(void *param) { int writeFid = (intptr_t)param; afs_int32 code = 0; code = InitRPC(&dumpSyncPtr->ut, LOCKREAD, 1); if (code) goto error_exit; code = writeDatabase(dumpSyncPtr->ut, writeFid); if (code) LogError(code, "writeDatabase failed\n"); code = close(writeFid); if (code) LogError(code, "pipe writer close failed\n"); LogDebug(5, "writeDatabase complete\n"); error_exit: if (dumpSyncPtr->ut) ubik_EndTrans(dumpSyncPtr->ut); return (void *)(intptr_t)(code); }
afs_int32 FreeLock(struct rx_call *call, afs_uint32 lockHandle) { db_lockP lockPtr = 0; struct ubik_trans *ut; afs_int32 code; if (callPermitted(call) == 0) return (BUDB_NOTPERMITTED); code = InitRPC(&ut, LOCKWRITE, 1); if (code) return (code); if (checkLockHandle(ut, lockHandle) == 0) ABORT(BUDB_BADARGUMENT); lockPtr = &db.h.textLocks[lockHandle - 1]; lockPtr->lockState = 0; /* unlock it */ lockPtr->lockTime = 0; lockPtr->expires = 0; lockPtr->instanceId = 0; dbwrite(ut, DBH_POS(lockPtr), (char *)lockPtr, sizeof(db_lockT)); code = ubik_EndTrans(ut); return (code); abort_exit: ubik_AbortTrans(ut); return (code); }
afs_int32 GetInstanceId(struct rx_call *call, afs_uint32 *instanceId) { struct ubik_trans *ut; afs_int32 code; afs_int32 instanceValue; LogDebug(4, "GetInstanceId:\n"); /* *** Allow anyone to get the instance id *** * if ( callPermitted(call) == 0 ) * return(BUDB_NOTPERMITTED); */ code = InitRPC(&ut, LOCKWRITE, 1); if (code) return (code); instanceValue = ntohl(db.h.lastInstanceId) + 1; set_header_word(ut, lastInstanceId, htonl(instanceValue)); code = ubik_EndTrans(ut); return (code); }
int SSAMPLE_Inc(struct rx_call *call) { afs_int32 code, temp; struct ubik_trans *tt; struct timeval tv; code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt); if (code) return code; printf("about to set lock\n"); /* now set database locks. Must do this or people may read uncommitted * data. Note that we're just setting a lock at position 1, which is * this program's convention for locking the whole database */ code = ubik_SetLock(tt, 1, 1, LOCKWRITE); printf("now have lock\n"); if (code) { ubik_AbortTrans(tt); return code; } /* sleep for a little while to make it possible for us to test for some * race conditions */ if (sleepTime) { tv.tv_sec = sleepTime; tv.tv_usec = 0; #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif } /* read the original value */ code = ubik_Read(tt, &temp, sizeof(afs_int32)); if (code == UEOF) { /* short read */ temp = 0; } else if (code) { ubik_AbortTrans(tt); return code; } temp++; /* bump the value here */ /* reset the file pointer back to where it was before the read */ code = ubik_Seek(tt, 0, 0); if (code) { ubik_AbortTrans(tt); return code; } /* write the data back */ code = ubik_Write(tt, &temp, sizeof(afs_int32)); if (code) { ubik_AbortTrans(tt); return code; } /* finally, we commit the transaction */ code = ubik_EndTrans(tt); temp = 0; return code; }
afs_int32 GetLock(struct rx_call *call, afs_uint32 instanceId, afs_int32 lockName, afs_int32 expiration, afs_uint32 *lockHandle) { struct timeval tv; db_lockP lockPtr; struct ubik_trans *ut; afs_int32 code; if (callPermitted(call) == 0) return (BUDB_NOTPERMITTED); if ((lockName < 0) || (lockName >= TB_NUM)) return (BUDB_BADARGUMENT); /* get the current time */ gettimeofday(&tv, 0); code = InitRPC(&ut, LOCKWRITE, 1); if (code) return (code); lockPtr = &db.h.textLocks[lockName]; if ((ntohl(lockPtr->lockState) != 0) /* lock set */ &&(ntohl(lockPtr->expires) > tv.tv_sec) /* not expired */ ) { if (ntohl(lockPtr->instanceId) == instanceId) code = BUDB_SELFLOCKED; else code = BUDB_LOCKED; goto abort_exit; } lockPtr->lockState = htonl(1); /* lock it */ lockPtr->lockTime = htonl(tv.tv_sec); /* when locked */ lockPtr->expires = htonl(tv.tv_sec + expiration); lockPtr->instanceId = htonl(instanceId); code = dbwrite(ut, DBH_POS(lockPtr), (char *)lockPtr, sizeof(db_lockT)); if (code) ABORT(code); *lockHandle = (afs_uint32) (lockName + 1); code = ubik_EndTrans(ut); return (code); abort_exit: ubik_AbortTrans(ut); return (code); }
int SSAMPLE_Get(struct rx_call *call, afs_int32 *gnumber) { afs_int32 code, temp; struct ubik_trans *tt; struct timeval tv; /* start with a read transaction, since we're only going to do read * operations in this transaction. */ code = ubik_BeginTrans(dbase, UBIK_READTRANS, &tt); if (code) return code; printf("about to set lock\n"); /* obtain a read lock, so we don't read data the other guy is writing */ code = ubik_SetLock(tt, 1, 1, LOCKREAD); printf("now have lock\n"); if (code) { ubik_AbortTrans(tt); return code; } /* sleep to allow races */ if (sleepTime) { tv.tv_sec = sleepTime; tv.tv_usec = 0; #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif } /* read the value */ code = ubik_Read(tt, &temp, sizeof(afs_int32)); if (code == UEOF) { /* premature eof, use 0 */ temp = 0; } else if (code) { ubik_AbortTrans(tt); return code; } *gnumber = temp; /* end the transaction, automatically releasing locks */ code = ubik_EndTrans(tt); return code; }
static void * CheckSignal(void *unused) { int i, errorcode; struct vl_ctx ctx; if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, VLGETSTATS - VL_LOWEST_OPCODE))) return (void *)(intptr_t)errorcode; VLog(0, ("Dump name hash table out\n")); for (i = 0; i < HASHSIZE; i++) { HashNDump(&ctx, i); } VLog(0, ("Dump id hash table out\n")); for (i = 0; i < HASHSIZE; i++) { HashIdDump(&ctx, i); } return ((void *)(intptr_t)ubik_EndTrans(ctx.trans)); } /*CheckSignal */
static void * CheckSignal(void *unused) { register int i, errorcode; struct ubik_trans *trans; if (errorcode = Init_VLdbase(&trans, LOCKREAD, VLGETSTATS - VL_LOWEST_OPCODE)) return (void *)errorcode; VLog(0, ("Dump name hash table out\n")); for (i = 0; i < HASHSIZE; i++) { HashNDump(trans, i); } VLog(0, ("Dump id hash table out\n")); for (i = 0; i < HASHSIZE; i++) { HashIdDump(trans, i); } return ((void *)ubik_EndTrans(trans)); } /*CheckSignal */
afs_int32 GetTextVersion(struct rx_call *call, afs_int32 textType, afs_uint32 *tversion) { afs_int32 code; struct ubik_trans *ut; if (callPermitted(call) == 0) return (BUDB_NOTPERMITTED); if ((textType < 0) || (textType >= TB_NUM)) return (BUDB_BADARGUMENT); code = InitRPC(&ut, LOCKREAD, 1); if (code) return (code); *tversion = ntohl(db.h.textBlock[textType].version); code = ubik_EndTrans(ut); return (code); }
int SSAMPLE_Trun(struct rx_call *call) { afs_int32 code; struct ubik_trans *tt; struct timeval tv; /* truncation operation requires a write transaction, too */ code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt); if (code) return code; printf("about to set lock\n"); /* lock the database */ code = ubik_SetLock(tt, 1, 1, LOCKWRITE); printf("now have lock\n"); if (code) { ubik_AbortTrans(tt); return code; } if (sleepTime) { tv.tv_sec = sleepTime; tv.tv_usec = 0; #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif } /* shrink the file */ code = ubik_Truncate(tt, 0); if (code) { ubik_AbortTrans(tt); return code; } /* commit */ code = ubik_EndTrans(tt); return code; }
afs_int32 RestoreDbHeader(struct rx_call *call, struct DbHeader *header) { struct ubik_trans *ut = 0; afs_int32 code = 0; extern struct memoryDB db; if (callPermitted(call) == 0) ERROR(BUDB_NOTPERMITTED); code = InitRPC(&ut, LOCKWRITE, 1); if (code) goto error_exit; if (header->dbversion != ntohl(db.h.version)) ERROR(BUDB_VERSIONMISMATCH); /* merge rather than replace the header information */ if (db.h.lastDumpId < htonl(header->lastDumpId)) db.h.lastDumpId = htonl(header->lastDumpId); if (db.h.lastTapeId < htonl(header->lastTapeId)) db.h.lastTapeId = htonl(header->lastTapeId); if (db.h.lastInstanceId < htonl(header->lastInstanceId)) db.h.lastInstanceId = htonl(header->lastInstanceId); code = dbwrite(ut, 0, (char *)&db.h, sizeof(db.h)); if (code) code = BUDB_IO; error_exit: if (ut) ubik_EndTrans(ut); return (code); }
afs_int32 UDP_GetTicket(int ksoc, struct packet *pkt, afs_int32 kvno, char *authDomain, char *ticket, int ticketLen, char *auth, int authLen) { afs_int32 code; struct ktc_encryptionKey tgskey; char name[MAXKTCNAMELEN]; char inst[MAXKTCNAMELEN]; char cell[MAXKTCREALMLEN]; struct ktc_encryptionKey authSessionKey; afs_int32 host; Date start; Date authEnd; Date now = time(0); int celllen; int import; char *packet; int slen; int byteOrder = pkt->byteOrder; char sname[MAXKTCNAMELEN]; char sinst[MAXKTCNAMELEN]; afs_int32 time_ws; unsigned char life; struct ubik_trans *tt; afs_int32 to; struct kaentry caller; struct kaentry server; Date reqEnd; struct ktc_encryptionKey sessionKey; int newTicketLen; char newTicket[MAXKTCTICKETLEN]; char cipher[2 * MAXKTCTICKETLEN]; /* put encrypted part of answer here */ int cipherLen; struct packet ans; COUNT_REQ(UGetTicket); if ((code = InitAuthServ(&tt, LOCKREAD, this_op))) goto fail; code = ka_LookupKvno(tt, KA_TGS_NAME, ((strlen(authDomain) > 0) ? authDomain : lrealm), kvno, &tgskey); if (code) goto abort; code = tkt_DecodeTicket(ticket, ticketLen, &tgskey, name, inst, cell, &authSessionKey, &host, &start, &authEnd); pkt->name = name; pkt->inst = inst; pkt->realm = cell; if (code) { code = KERB_ERR_AUTH_EXP; /* was KANOAUTH */ goto abort; } save_principal(udptgsPrincipal, name, inst, cell); code = tkt_CheckTimes(start, authEnd, now); if (code <= 0) { if (code == -1) { code = KERB_ERR_SERVICE_EXP; /* was RXKADEXPIRED */ goto abort; } code = KERB_ERR_AUTH_EXP; /* was KANOAUTH */ goto abort; } celllen = strlen(cell); import = 0; if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0)) import = 1; if (import && (celllen == 0)) { code = KERB_ERR_PKT_VER; /* was KABADTICKET */ goto abort; } if (celllen == 0) { strncpy(cell, lrealm, MAXKTCREALMLEN - 1); cell[MAXKTCREALMLEN - 1] = 0; }; if (!krb4_cross && strcmp(lrealm, cell) != 0) { code = KERB_ERR_PRINCIPAL_UNKNOWN; goto abort; } if (krb_udp_debug) { printf("UGetTicket: got ticket from '%s'.'%s'@'%s'\n", name, inst, cell); } code = check_auth(pkt, auth, authLen, &authSessionKey, name, inst, cell); if (code) goto abort; /* authenticator and all is OK so read actual request */ packet = pkt->rest; getint(time_ws); life = *(unsigned char *)packet++; getstr(sname); getstr(sinst); start = now; reqEnd = life_to_time(start, life); if (krb_udp_debug) { printf("UGetTicket: request for server '%s'.'%s'\n", sname, sinst); } save_principal(udptgsServerPrincipal, sname, sinst, 0); if (import) { strcpy(caller.userID.name, name); strcpy(caller.userID.instance, inst); caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME); } else { code = FindBlock(tt, name, inst, &to, &caller); if (code) goto abort; if (to == 0) { ka_PrintUserID("GetTicket: User ", name, inst, " unknown.\n"); code = KERB_ERR_PRINCIPAL_UNKNOWN; /* KANOENT */ goto abort; } if (ntohl(caller.flags) & KAFNOTGS) { code = KERB_ERR_AUTH_EXP; /* was KABADUSER */ goto abort; } } code = FindBlock(tt, sname, sinst, &to, &server); /* get server's entry */ if (code) goto abort; if (to == 0) { /* entry not found */ ka_PrintUserID("GetTicket: Server ", sname, sinst, " unknown.\n"); code = KERB_ERR_PRINCIPAL_UNKNOWN; /* KANOENT */ goto abort; } code = ubik_EndTrans(tt); if (code) goto fail; if (ntohl(server.flags) & KAFNOSEAL) return KABADSERVER; code = DES_new_random_key(ktc_to_cblock(&sessionKey)); if (code) { code = KERB_ERR_NULL_KEY; /* was KANOKEYS */ goto fail; } reqEnd = umin(umin(reqEnd, authEnd), umin(start + ntohl(caller.max_ticket_lifetime), start + ntohl(server.max_ticket_lifetime))); code = tkt_MakeTicket(newTicket, &newTicketLen, &server.key, caller.userID.name, caller.userID.instance, cell, start, reqEnd, &sessionKey, htonl(pkt->from.sin_addr.s_addr), server.userID.name, server.userID.instance); if (code) goto fail; cipherLen = sizeof(cipher); code = create_cipher(cipher, &cipherLen, &sessionKey, sname, sinst, start, reqEnd, ntohl(server.key_version), newTicket, newTicketLen, &authSessionKey); if (code) goto fail; code = create_reply(&ans, name, inst, start, reqEnd, 0, cipher, cipherLen); if (code) goto fail; code = sendto(ksoc, ans.data, ans.len, 0, (struct sockaddr *)&pkt->from, sizeof(pkt->from)); if (code != ans.len) { perror("calling sendto"); code = -1; goto fail; } if (cipherLen != 0) { KALOG(name, inst, sname, sinst, NULL, host, LOG_GETTICKET); } osi_audit(UDPGetTicketEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_STR, cell, AUD_STR, sname, AUD_STR, sinst, AUD_END); return 0; abort: ubik_AbortTrans(tt); fail: osi_audit(UDPGetTicketEvent, code, AUD_STR, name, AUD_STR, inst, AUD_STR, NULL, AUD_STR, NULL, AUD_STR, NULL, AUD_END); return code; }
afs_int32 UDP_Authenticate(int ksoc, struct sockaddr_in *client, char *name, char *inst, Date startTime, Date endTime, char *sname, char *sinst) { struct ubik_trans *tt; afs_int32 to; /* offset of block */ struct kaentry tentry; afs_int32 tgskvno; /* key version of service key */ struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */ int tgt; Date now = time(0); afs_int32 code; char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */ int ticketLen; struct ktc_encryptionKey sessionKey; /* we have to invent a session key */ char cipher[2 * MAXKTCTICKETLEN]; /* put encrypted part of answer here */ int cipherLen; struct packet ans; COUNT_REQ(UAuthenticate); if (!name_instance_legal(name, inst)) return KERB_ERR_NAME_EXP; /* KABADNAME */ if ((code = InitAuthServ(&tt, LOCKREAD, this_op))) return code; code = FindBlock(tt, name, inst, &to, &tentry); if (code) goto abort; if (to) { /* if user exists check other stuff */ afs_int32 sto; struct kaentry sentry; save_principal(udpAuthPrincipal, name, inst, 0); tgt = ((strcmp(sname, KA_TGS_NAME) == 0) && (strcmp(sinst, lrealm) == 0)); if ((ntohl(tentry.user_expiration) < now) || (tgt && (ntohl(tentry.flags) & KAFNOTGS))) { code = KERB_ERR_NAME_EXP; /* KABADUSER */ goto abort; } code = FindBlock(tt, KA_TGS_NAME, lrealm, &sto, &sentry); if (code) goto abort; if (sto == 0) { code = KANOENT; goto abort; } if ((ntohl(sentry.user_expiration) < now)) { code = KERB_ERR_NAME_EXP; /* XXX Could use another error code XXX */ goto abort; } if (abs(startTime - now) > KTC_TIME_UNCERTAINTY) { code = KERB_ERR_SERVICE_EXP; /* was KABADREQUEST */ goto abort; } if (tentry.misc_auth_bytes) { unsigned char misc_auth_bytes[4]; afs_uint32 temp; /* unsigned for safety */ afs_uint32 pwexpires; memcpy(&temp, tentry.misc_auth_bytes, sizeof(afs_uint32)); temp = ntohl(temp); unpack_long(temp, misc_auth_bytes); pwexpires = misc_auth_bytes[0]; if (pwexpires) { pwexpires = ntohl(tentry.change_password_time) + 24 * 60 * 60 * pwexpires; if (pwexpires < now) { code = KERB_ERR_AUTH_EXP; /* was KAPWEXPIRED */ goto abort; } } } /* make the ticket */ code = DES_new_random_key(ktc_to_cblock(&sessionKey)); if (code) { code = KERB_ERR_NULL_KEY; /* was KANOKEYS */ goto abort; } endTime = umin(endTime, startTime + ntohl(tentry.max_ticket_lifetime)); if ((code = ka_LookupKey(tt, sname, sinst, &tgskvno, &tgskey)) || (code = tkt_MakeTicket(ticket, &ticketLen, &tgskey, name, inst, lrealm, startTime, endTime, &sessionKey, htonl(client->sin_addr.s_addr), sname, sinst))) goto abort; cipherLen = sizeof(cipher); code = create_cipher(cipher, &cipherLen, &sessionKey, sname, sinst, startTime, endTime, tgskvno, ticket, ticketLen, &tentry.key); if (code) goto abort; } else { /* no such user */ cipherLen = 0; tentry.key_version = 0; } code = ubik_EndTrans(tt); if (code) goto fail; code = create_reply(&ans, name, inst, startTime, endTime, ntohl(tentry.key_version), cipher, cipherLen); if (code) goto fail; if (krb_udp_debug) { printf("Sending %d bytes ending in: ", ans.len); ka_PrintBytes(ans.data + ans.len - 8, 8); printf("\n"); } code = sendto(ksoc, ans.data, ans.len, 0, (struct sockaddr *)client, sizeof(*client)); if (code != ans.len) { perror("calling sendto"); code = -1; goto fail; } KALOG(name, inst, sname, sinst, NULL, client->sin_addr.s_addr, LOG_AUTHENTICATE); if (cipherLen != 0) { KALOG(name, inst, sname, sinst, NULL, client->sin_addr.s_addr, LOG_TGTREQUEST); } osi_audit(UDPAuthenticateEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_END); return 0; abort: COUNT_ABO; ubik_AbortTrans(tt); fail: osi_audit(UDPAuthenticateEvent, code, AUD_STR, name, AUD_STR, inst, AUD_END); return code; }
afs_int32 GetText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType, afs_int32 maxLength, afs_int32 offset, afs_int32 *nextOffset, charListT *charListPtr) { struct ubik_trans *ut = 0; struct block block; afs_int32 transferSize, chunkSize; afs_int32 blockOffset; dbadr lastBlockAddr; afs_int32 nblocks; struct textBlock *tbPtr; afs_int32 textRemaining; char *textPtr; afs_int32 code; LogDebug(5, "GetText: type %d, offset %d, nextOffset %"AFS_PTR_FMT ", maxLength %d\n", textType, offset, nextOffset, maxLength); if (callPermitted(call) == 0) { code = BUDB_NOTPERMITTED; goto no_xfer_abort; } /* check parameters */ if ((offset < 0) || (textType < 0) || (textType >= TB_NUM) ) { code = BUDB_BADARGUMENT; goto no_xfer_abort; } /* start the transaction */ code = InitRPC(&ut, LOCKWRITE, 1); if (code) goto no_xfer_abort; /* fetch the lock state */ if (checkLockHandle(ut, lockHandle) == 0) { code = BUDB_NOTLOCKED; goto no_xfer_abort; } tbPtr = &db.h.textBlock[textType]; if ((ntohl(tbPtr->size) > 0) && (offset >= ntohl(tbPtr->size)) ) { code = BUDB_BADARGUMENT; goto no_xfer_abort; } LogDebug(5, "GetText: store size is %d\n", ntohl(tbPtr->size)); /* compute minimum of remaining text or user buffer */ textRemaining = ntohl(tbPtr->size) - offset; transferSize = MIN(textRemaining, maxLength); /* allocate the transfer storage */ if (transferSize <= 0) { charListPtr->charListT_len = 0L; charListPtr->charListT_val = NULL; } else { charListPtr->charListT_len = transferSize; charListPtr->charListT_val = (char *)malloc(transferSize); if (charListPtr->charListT_val == 0) ABORT(BUDB_NOMEM); } textPtr = charListPtr->charListT_val; *nextOffset = offset + transferSize; /* setup the datablock. read and discard all blocks up to the one the * offset specifies */ nblocks = offset / BLOCK_DATA_SIZE; lastBlockAddr = ntohl(tbPtr->textAddr); while (nblocks--) { code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block)); if (code) ABORT(BUDB_IO); lastBlockAddr = ntohl(block.h.next); } while (transferSize > 0) { code = dbread(ut, lastBlockAddr, (char *)&block, sizeof(block)); if (code) ABORT(BUDB_IO); LogDebug(5, "fetched block %d\n", lastBlockAddr); /* compute the data size to extract */ blockOffset = offset % BLOCK_DATA_SIZE; textRemaining = BLOCK_DATA_SIZE - blockOffset; chunkSize = min(textRemaining, transferSize); memcpy(textPtr, &block.a[blockOffset], chunkSize); /* LogDebug(5, "transfering %d bytes: %s\n", chunkSize, textPtr); */ transferSize -= chunkSize; offset += chunkSize; textPtr += chunkSize; if (transferSize) { /* setup lastBlockAddr */ lastBlockAddr = ntohl(block.h.next); } } if (*nextOffset == ntohl(tbPtr->size)) { /* all done */ *nextOffset = -1; } /* error_exit: */ code = ubik_EndTrans(ut); /* printf("in error exit, code=%ld\n", code); */ return (code); no_xfer_abort: charListPtr->charListT_len = 0; charListPtr->charListT_val = (char *)malloc(0); abort_exit: if (ut) ubik_AbortTrans(ut); /* printf("in abort exit, code=%ld\n", code); */ return (code); }
afs_int32 SaveText(struct rx_call *call, afs_uint32 lockHandle, afs_int32 textType, afs_int32 offset, afs_int32 flags, charListT *charListPtr) { struct ubik_trans *ut; struct block diskBlock; dbadr diskBlockAddr; afs_int32 remainingInBlock, chunkSize; struct textBlock *tbPtr; afs_int32 textLength = charListPtr->charListT_len; char *textptr = charListPtr->charListT_val; afs_int32 code; LogDebug(5, "SaveText: type %d, offset %d, length %d\n", textType, offset, textLength); if (callPermitted(call) == 0) return (BUDB_NOTPERMITTED); if ((textLength > BLOCK_DATA_SIZE) || (offset < 0)) return (BUDB_BADARGUMENT); code = InitRPC(&ut, LOCKWRITE, 1); if (code) return (code); /* fetch the lock state */ if (checkLockHandle(ut, lockHandle) == 0) ABORT(BUDB_NOTLOCKED); if ((textType < 0) || (textType >= TB_NUM)) ABORT(BUDB_BADARGUMENT); tbPtr = &db.h.textBlock[textType]; LogDebug(5, "SaveText: lockHandle %d textType %d offset %d flags %d txtlength %d\n", lockHandle, textType, offset, flags, textLength); if (offset == 0) { /* release any blocks from previous transactions */ diskBlockAddr = ntohl(tbPtr->newTextAddr); freeOldBlockChain(ut, diskBlockAddr); if (textLength) { code = AllocBlock(ut, &diskBlock, &diskBlockAddr); if (code) ABORT(code); LogDebug(5, "allocated block %d\n", diskBlockAddr); /* set block type */ diskBlock.h.type = text_BLOCK; /* save it in the database header */ tbPtr->newsize = 0; tbPtr->newTextAddr = htonl(diskBlockAddr); dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr, sizeof(struct textBlock)); } else { tbPtr->newsize = 0; tbPtr->newTextAddr = 0; } } else { /* non-zero offset */ int nblocks; if (offset != ntohl(tbPtr->newsize)) ABORT(BUDB_BADARGUMENT); /* locate the block to which offset refers */ nblocks = offset / BLOCK_DATA_SIZE; diskBlockAddr = ntohl(tbPtr->newTextAddr); if (diskBlockAddr == 0) ABORT(BUDB_BADARGUMENT); code = dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock)); if (code) ABORT(code); while (nblocks--) { diskBlockAddr = ntohl(diskBlock.h.next); code = dbread(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock)); if (code) ABORT(code); } } /* diskBlock and diskBlockAddr now point to the last block in the chain */ while (textLength) { /* compute the transfer size */ remainingInBlock = (BLOCK_DATA_SIZE - (offset % BLOCK_DATA_SIZE)); chunkSize = MIN(remainingInBlock, textLength); /* copy in the data */ memcpy(&diskBlock.a[offset % BLOCK_DATA_SIZE], textptr, chunkSize); /* LogDebug(5, "text is %s\n", textptr); */ textLength -= chunkSize; textptr += chunkSize; offset += chunkSize; tbPtr->newsize = htonl(ntohl(tbPtr->newsize) + chunkSize); if (textLength > 0) { afs_int32 prevBlockAddr; afs_int32 linkOffset; afs_int32 linkValue; /* have to add another block to the chain */ code = dbwrite(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock)); if (code) ABORT(code); prevBlockAddr = (afs_int32) diskBlockAddr; code = AllocBlock(ut, &diskBlock, &diskBlockAddr); if (code) ABORT(code); LogDebug(5, "allocated block %d\n", diskBlockAddr); /* set block type */ diskBlock.h.type = text_BLOCK; /* now have to update the previous block's link */ linkOffset = (afs_int32) ((char*)& diskBlock.h.next - (char*)& diskBlock); linkValue = htonl(diskBlockAddr); code = dbwrite(ut, (afs_int32) prevBlockAddr + linkOffset, (char *)&linkValue, sizeof(afs_int32)); if (code) ABORT(code); } else { /* just write the old block */ code = dbwrite(ut, diskBlockAddr, (char *)&diskBlock, sizeof(diskBlock)); if (code) ABORT(code); } } if (flags & BUDB_TEXT_COMPLETE) { /* done */ /* this was the last chunk of text */ diskBlockAddr = ntohl(tbPtr->textAddr); freeOldBlockChain(ut, diskBlockAddr); tbPtr->textAddr = tbPtr->newTextAddr; tbPtr->newTextAddr = 0; tbPtr->size = tbPtr->newsize; tbPtr->newsize = 0; tbPtr->version = htonl(ntohl(tbPtr->version) + 1); /* saveTextToFile(ut, tbPtr); */ } /* update size and other text header info */ code = dbwrite(ut, (char *)tbPtr - (char *)&db.h, (char *)tbPtr, sizeof(struct textBlock)); if (code) ABORT(code); /*error_exit: */ code = ubik_EndTrans(ut); return (code); abort_exit: ubik_AbortTrans(ut); return (code); }