Beispiel #1
0
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;
}
Beispiel #2
0
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);
}
Beispiel #3
0
int
SSAMPLE_Test(struct rx_call *call)
{
    afs_int32 code, temp;
    struct ubik_trans *tt;
    struct timeval tv;

    /* first start a new transaction.  Must be a write transaction since
     * we're going to change some data (with ubik_Write) */
    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) {
	printf("short read, using 0\n");
	temp = 0;
    } else if (code) {
	ubik_AbortTrans(tt);
	return code;
    }
    ubik_AbortTrans(tt);	/* surprise! pretend something went wrong */
    return code;
}
Beispiel #4
0
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;
}
Beispiel #5
0
void *
dumpWatcher(void *unused)
{
    afs_int32 code;

    while (1) {			/*w */

        /* printf("dumpWatcher\n"); */
        ObtainWriteLock(&dumpSyncPtr->ds_lock);

        if (dumpSyncPtr->statusFlags == 0) {
            /* dump has finished */
            goto exit;
        }

        /* check time to live */
        if (time(0) > dumpSyncPtr->timeToLive) {	/*i */
            /* dump has exceeded the allocated time - terminate it */
            LogError(0, "Database dump timeout exceeded: %s",
                     ctime(&dumpSyncPtr->timeToLive));
            LogError(0, "Terminating database dump\n");

            close(dumpSyncPtr->pipeFid[0]);
            close(dumpSyncPtr->pipeFid[1]);
#ifdef AFS_PTHREAD_ENV
            assert(pthread_cancel(dumpSyncPtr->dumperPid) == 0);
#else
            code = LWP_DestroyProcess(dumpSyncPtr->dumperPid);
            if (code)
                LogError(code, "dumpWatcher: failed to kill dump thread\n");
#endif

            if (dumpSyncPtr->ut) {
                code = ubik_AbortTrans(dumpSyncPtr->ut);
                if (code)
                    LogError(code, "Aborting dump transaction\n");
            }

            memset(dumpSyncPtr, 0, sizeof(*dumpSyncPtr));
            goto exit;
        }
        /*i */
        ReleaseWriteLock(&dumpSyncPtr->ds_lock);
#ifdef AFS_PTHREAD_ENV
        sleep(5);
#else
        IOMGR_Sleep(5);
#endif
    }				/*w */

exit:
    ReleaseWriteLock(&dumpSyncPtr->ds_lock);
    /* printf("dumpWatcher exit\n"); */
    return (0);
}
Beispiel #6
0
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);
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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);
}
Beispiel #11
0
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);
}