/* * Attempt to auto-detect the HRM type based on some information in the file. * This may not always succeed, but it seems to work relatively well. */ static S725_HRM_Type workout_detect_hrm_type(BUF *buf) { int duration = 0; int samples; int laps; int header = 0; int bps = 0; int bpl = 0; int ri; if (buf_len(buf) <= 37) { log_error("workout_detect_hrm_type: buffer size too small"); return S725_HRM_UNKNOWN; } if (buf_getc(buf, 34) == 0 && buf_getc(buf, 36) == 251) { return S725_HRM_S610; } if (buf_getc(buf, 37) == 251 && (buf_getc(buf, 35) == 0 || buf_getc(buf, 35) == 48)) { /* this is either an s725 or s625x or...? */ if ((ri = workout_get_recording_interval(buf_getc(buf, 27))) != 0) { /* compute the number of bytes per sample and per lap */ bps = workout_bytes_per_sample(buf_getc(buf, 26)); bpl = workout_bytes_per_lap(S725_HRM_UNKNOWN, buf_getc(buf, 26), buf_getc(buf, 23)); /* obtain the number of laps and samples in the file */ duration = buf_getbcd(buf, 16) + 60 * (buf_getbcd(buf, 17) + 60 * buf_getbcd(buf, 18)); samples = duration / ri + 1; laps = buf_getbcd(buf, 21); /* now compute the size of the file header */ header = buf_len(buf) - samples * bps - laps * bpl; /* * based on the header size, we can make a guess at the * HRM type. note that this will NOT work if the file was * truncated due to the watch memory filling up before * recording was stopped. * * assume it's an S725 unless the header size matches * the S625x header size. */ if (header == S725_HEADER_SIZE_S625X) { return S725_HRM_S625X; } else { return S725_HRM_S725; } } } return S725_HRM_UNKNOWN; }
static struct object *load_xbm( struct pike_string *data ) { int width, height; int x, y; struct buffer buff; struct buffer *b = &buff; rgb_group *dest; struct object *io; buff.str = data->str; buff.len = data->len; if(!buf_search( b, '#' ) || !buf_search( b, ' ' ) || !buf_search( b, ' ' )) Pike_error("This is not a XBM image!\n"); width = atoi(b->str); if(width <= 0) Pike_error("This is not a XBM image!\n"); if(!buf_search( b, '#' ) || !buf_search( b, ' ' ) || !buf_search( b, ' ' )) Pike_error("This is not a XBM image!\n"); height = atoi(b->str); if(height <= 0) Pike_error("This is not a XBM image!\n"); if(!buf_search( b, '{' )) Pike_error("This is not a XBM image!\n"); push_int( width ); push_int( height ); io = clone_object( image_program, 2 ); dest = ((struct image *)get_storage(io, image_program))->img; /* .. the code below asumes black if the read fails.. */ for(y=0; y<height; y++) { int next_byte, cnt; for(x=0; x<width;) { if(buf_search( b, 'x' )) { next_byte = (hextoint(buf_getc( b ))*0x10) | hextoint(buf_getc( b )); for(cnt=0; cnt<8&&x<width; cnt++,x++) { if((next_byte&(1<<(x%8)))) dest->r = dest->g = dest->b = 255; dest++; } } else Pike_error("This is not a XBM image!\n"); } } return io; }
static void workout_read_preamble(workout_t *w, BUF *buf) { if (buf_len(buf) <= 10) { log_error("workout_read_preamble: buffer too small"); return /* TODO: ERROR */; } /* number of bytes in the buffer (including these two) */ w->bytes = buf_getc(buf, 0) + (buf_getc(buf, 1) << 8); w->exercise_number = buf_getc(buf, 2); if (w->exercise_number > 0 && w->exercise_number <= 5) { workout_label_extract(buf, 3, &w->exercise_label, 7); } else { strncpy(w->exercise_label, "<empty>", sizeof(w->exercise_label) - 1); w->exercise_label[sizeof(w->exercise_label) - 1] = '\0'; } }
static void workout_read_date(workout_t *w, BUF *buf) { /* date of workout */ w->date.tm_sec = buf_getbcd(buf, 10); w->date.tm_min = buf_getbcd(buf, 11); w->date.tm_hour = buf_getbcd(buf, 12) & 0x7f; /* PATCH for AM/PM mode detection from Berend Ozceri */ w->ampm = S725_AM_PM_MODE_UNSET; if (buf_getc(buf, 13) & 0x80) w->ampm |= S725_AM_PM_MODE_SET; if (buf_getc(buf, 12) & 0x80) w->ampm |= S725_AM_PM_MODE_PM; w->date.tm_hour += (buf_getc(buf, 13) & 0x80) ? /* am/pm mode? */ ((buf_getc(buf, 12) & 0x80) ? ((w->date.tm_hour < 12) ? 12 : 0) : /* yes, pm set */ ((w->date.tm_hour >= 12) ? -12 : 0)) : /* yes, pm unset */ 0; /* no */ w->date.tm_mon = (buf_getc(buf, 15) & 0x0f) - 1; w->date.tm_mday = buf_getbcd(buf, 13) & 0x7f; w->date.tm_year = 100 + buf_getbcd(buf, 14); w->date.tm_isdst = -1; /* Daylight savings time not known yet? */ w->unixtime = mktime(&w->date); }
static workout_t * workout_extract(BUF *buf, S725_HRM_Type type) { workout_t *w = NULL; int ok = 1; if ((w = calloc(1, sizeof(workout_t))) == NULL) { log_info("workout_extract: calloc: %s", strerror(errno)); return NULL; } /* Define the type of the HRM */ w->type = type; /* Now extract the header data */ workout_read_preamble(w, buf); workout_read_date(w, buf); workout_read_duration(w, buf, 15); if (buf_get_readerr(buf)) { log_info("workout_extract: readerr after header (%d > %d)", buf_get_readerr_offset(buf), buf_len(buf)); workout_free(w); return NULL; } w->avg_hr = buf_getc(buf, 19); w->max_hr = buf_getc(buf, 20); w->laps = buf_getbcd(buf, 21); w->manual_laps = buf_getbcd(buf, 22); w->interval_mode = buf_getc(buf, 23); w->user_id = buf_getbcd(buf, 24); workout_read_units(w, buf); if (buf_get_readerr(buf)) { log_info("workout_extract: readerr after units (%d > %d)", buf_get_readerr_offset(buf), buf_len(buf)); workout_free(w); return NULL; } /* recording mode and interval */ if (w->type == S725_HRM_S610) { w->mode = 0; workout_read_recording_interval (w, buf, 26); workout_read_hr_limits (w, buf, 28); workout_read_bestlap_split (w, buf, 65); workout_read_energy (w, buf, 69); workout_read_cumulative_exercise (w, buf, 75); } else { w->mode = buf_getc(buf, 26); workout_read_recording_interval (w, buf, 27); workout_read_hr_limits (w, buf, 29); workout_read_bestlap_split (w, buf, 66); workout_read_energy (w, buf, 70); workout_read_cumulative_exercise (w, buf, 76); workout_read_ride_info (w, buf, 79); } if (buf_get_readerr(buf)) { log_info("workout_extract: readerr after mode (%d > %d)", buf_get_readerr_offset(buf), buf_len(buf)); workout_free(w); return NULL; } ok = workout_read_laps(w, buf); if (buf_get_readerr(buf)) { log_info("workout_extract: readerr after read laps (%d > %d)", buf_get_readerr_offset(buf), buf_len(buf)); workout_free(w); return NULL; } if (!ok) { workout_free(w); return NULL; } ok = workout_read_samples(w, buf); if (buf_get_readerr(buf)) { log_info("workout_extract: readerr after read samples (%d > %d)", buf_get_readerr_offset(buf), buf_len(buf)); workout_free(w); return NULL; } if (!ok) { workout_free(w); return NULL; } workout_compute_speed_info(w); return w; }
int v2body(BUFFER *body) { int i, n; BUFFER *to, *newsgroups; BUFFER *temp, *out; BUFFER *line; int type = MSG_MAIL; int subject = 0; line = buf_new(); to = buf_new(); newsgroups = buf_new(); temp = buf_new(); out = buf_new(); n = buf_getc(body); for (i = 0; i < n; i++) { buf_get(body, line, 80); buf_chop(line); if (bufileft(line, "null:")) goto end; if (bufileft(line, "post:")) { type = MSG_POST; if (line->length > 5) { int j = 5; while (j < line->length && isspace(line->data[j])) j++; if (newsgroups->length > 0) buf_appends(newsgroups, ","); buf_append(newsgroups, line->data + j, line->length - j); } } else { if (to->length > 0) buf_appends(to, ","); buf_cat(to, line); } } if (to->length > 0) { buf_appends(out, "To: "); buf_cat(out, to); buf_nl(out); } if (newsgroups->length > 0) { buf_appends(out, "Newsgroups: "); buf_cat(out, newsgroups); buf_nl(out); } n = buf_getc(body); for (i = 0; i < n; i++) { buf_get(body, line, 80); buf_chop(line); if (bufileft(line, "Subject:")) subject = 1; buf_cat(out, line); buf_nl(out); } buf_rest(temp, body); buf_uncompress(temp); buf_set(body, temp); buf_reset(temp); if (buf_lookahead(body, line) == 0 && isline(line, HASHMARK)) { buf_getline(body, line); while (buf_getline(body, line) == 0) { if (bufileft(line, "subject:")) subject = 1; buf_cat(out, line); buf_nl(out); } } if (type == MSG_POST && !subject) buf_appends(out, "Subject: (no subject)\n"); buf_nl(out); buf_rest(out, body); buf_reset(body); mix_pool(out, type, -1); end: buf_free(line); buf_free(to); buf_free(newsgroups); buf_free(temp); buf_free(out); return (0); }
int mix2_decrypt(BUFFER *m) /* 0: ok * -1: error * -2: old message */ { int err = 0; int i,rsalen,rsalen_as_byte; BUFFER *privkey; BUFFER *keyid; BUFFER *dec, *deskey; BUFFER *packetid, *mid, *digest, *addr, *temp, *iv, *ivvec; int type, packet = 0, numpackets = 0, timestamp = 0; BUFFER *body; BUFFER *header, *out; BUFFER *otherdigest, *bodydigest, *antitag, *extract; BUFFER *ttedigest, *hkey, *aes_pre_key, *aes_header_key, *aes_body_key, *aes_tte_key, *aes_iv; BUFFER *trail; privkey = buf_new(); keyid = buf_new(); dec = buf_new(); deskey = buf_new(); packetid = buf_new(); mid = buf_new(); digest = buf_new(); addr = buf_new(); temp = buf_new(); iv = buf_new(); ivvec = buf_new(); body = buf_new(); header = buf_new(); out = buf_new(); otherdigest = buf_new(); bodydigest = buf_new(); antitag = buf_new(); extract = buf_new(); ttedigest = buf_new(); hkey = buf_new(); aes_pre_key = buf_new(); aes_header_key = buf_new(); aes_body_key = buf_new(); aes_tte_key = buf_new(); aes_iv = buf_new(); trail=buf_new(); aes_pre_key->sensitive=1; aes_body_key->sensitive=1; aes_tte_key->sensitive=1; dec->sensitive=1; deskey->sensitive=1; extract->sensitive=1; hkey->sensitive=1; privkey->sensitive=1; buf_get(m, keyid, 16); err = db_getseckey(keyid->data, privkey); if (err == -1) { errlog(WARNING, "rem2.c mix2_decrypt not found keyid %s\n", showdata(keyid,0)); goto end; } rsalen_as_byte=buf_getc(m); switch(rsalen_as_byte) { case 128: /* legacy 1024-bit */ rsalen_as_byte=1; rsalen=128; break; case 2: rsalen_as_byte=2; rsalen=256; break; case 3: rsalen_as_byte=3; rsalen=384; break; case 4: rsalen_as_byte=4; rsalen=512; break; default: err = -1; errlog(NOTICE, "problem with RSA key size encoded as %d\n", rsalen_as_byte); goto end; break; } assert(128==rsalen || 256==rsalen || 384==rsalen || 512==rsalen); buf_get(m, extract, rsalen); /* 3DES key and maybe more */ err = pk_decrypt(extract, privkey); if (err == -1) { err = -1; errlog(NOTICE, "Cannot decrypt message.\n"); goto end; } buf_append(body, m->data + 20 * 512, 10240); buf_get(m, iv, 8); buf_get(m, dec, 328); if (128==rsalen) { if (extract->length != 24) { err = -1; errlog(NOTICE, "Cannot decrypt message - RSA 1024 data has wrong length %d not 24.\n", extract->length); /* If this length is greater someone may have wrongly sent digests under 1k RSA. */ goto end; } buf_cat(deskey, extract); } else { if (extract->length != 216) { err = -1; errlog(NOTICE, "Cannot decrypt message - RSA (large key) data has wrong length %d.\n", extract->length); /* supposed to be: * 3DES * hmac key * hmac-sha256(18*512 headers) * hmac-sha256(body) * hmac-sha256(328-block) * aes_pre_key */ goto end; } /* antitagging measure */ buf_get(extract, deskey, 24); buf_get(extract, hkey, 64); buf_get(extract, otherdigest, 32); buf_get(extract, bodydigest, 32); buf_get(extract, ttedigest, 32); buf_get(extract, aes_pre_key, 32); buf_reset(temp); hmac_sha256(body, hkey, temp); if (!buf_eq(bodydigest, temp)) { errlog(NOTICE, "Antitagging test - wrong digest on body.\n"); err = -1; goto end; } buf_reset(temp); hmac_sha256(dec, hkey, temp); if (!buf_eq(ttedigest, temp)) { errlog(NOTICE, "Antitagging test - wrong digest on 328-block.\n"); err = -1; goto end; } /* There is one more test applicable if packet type is 0. */ derive_aes_keys(aes_pre_key, hkey, aes_header_key, aes_body_key, aes_tte_key, aes_iv); buf_aescrypt(dec, aes_tte_key, aes_iv, DECRYPT); } buf_crypt(dec, deskey, iv, DECRYPT); buf_get(dec, packetid, 16); buf_get(dec, deskey, 24); type = buf_getc(dec); switch (type) { case 0: if (rsalen>=256) { buf_append(antitag, m->data + 2*512, 2*512); buf_reset(temp); hmac_sha256(antitag, hkey, temp); if (!buf_eq(otherdigest, temp)) { errlog(NOTICE, "Antitagging test - wrong digest on later header\n"); err = -1; goto end; } } buf_get(dec, ivvec, 152); buf_get(dec, addr, 80); break; case 1: buf_get(dec, mid, 16); buf_get(dec, iv, 8); break; case 2: packet = buf_getc(dec); numpackets = buf_getc(dec); buf_get(dec, mid, 16); buf_get(dec, iv, 8); break; default: errlog(WARNING, "Unknown message type.\n"); err = -1; goto end; } if (dec->data[dec->ptr] == '0' && dec->data[dec->ptr + 1] == '0' && dec->data[dec->ptr + 2] == '0' && dec->data[dec->ptr + 3] == '0' && dec->data[dec->ptr + 4] == '\0') { dec->ptr += 5; timestamp = buf_geti_lo(dec); } else { errlog(LOG, "Ignoring message without timestamp.\n"); err = -1; goto end; } buf_get(dec, digest, 16); /* digest of this block, but not so far as to include the digest */ dec->length = dec->ptr - 16; /* ignore digest */ dec->ptr = dec->length; /* If using 1024-bit RSA this is the only integrity protection. (It is still present but less important with larger key sizes.) if (!isdigest_md5(dec, digest)) { errlog(NOTICE, "Message digest does not match.\n"); err = -1; goto end; } /* Statistics are gathered in the isnewid() function. */ switch (isnewid(packetid, rsalen_as_byte, timestamp * SECONDSPERDAY)) { case 0: err = -2; /* redundant message */ goto end; case -1: err = -1; /* future timestamp */ goto end; } if (rsalen == 128) { /* skip either 1 or 2 blocks of 512 bytes */ buf_append(trail, m->data + 512, 19*512); } else { /* and AES */ buf_aescrypt(body, aes_body_key, aes_iv, DECRYPT); buf_append(trail, m->data + 2*512, 19*512); buf_aescrypt(trail, aes_header_key, aes_iv, DECRYPT); } switch (type) { case 0: buf_chop(addr); buf_cat(out, addr); buf_nl(out); for (i = 0; i < 19; i++) { buf_reset(header); buf_append(header, trail->data + i * 512, 512); buf_reset(iv); buf_append(iv, ivvec->data + i * 8, 8); buf_crypt(header, deskey, iv, DECRYPT); buf_cat(out, header); } buf_reset(header); buf_pad(header, 512); /* one block of 512 random data regardless of RSA key size */ buf_cat(out, header); buf_reset(iv); buf_append(iv, ivvec->data + 144, 8); buf_crypt(body, deskey, iv, DECRYPT); buf_cat(out, body); mix_pool(out, INTERMEDIATE, -1); break; case 1: buf_crypt(body, deskey, iv, DECRYPT); err = v2body_setlen(body); if (err == -1) goto end; assert(body->ptr == 4); v2body(body); break; case 2: buf_crypt(body, deskey, iv, DECRYPT); v2partial(body, mid, packet, numpackets); break; } end: buf_free(addr); buf_free(aes_body_key); buf_free(aes_header_key); buf_free(aes_iv); buf_free(aes_pre_key); buf_free(aes_tte_key); buf_free(antitag); buf_free(body); buf_free(bodydigest); buf_free(dec); buf_free(deskey); buf_free(digest); buf_free(extract); buf_free(header); buf_free(hkey); buf_free(iv); buf_free(ivvec); buf_free(keyid); buf_free(mid); buf_free(otherdigest); buf_free(out); buf_free(packetid); buf_free(privkey); buf_free(temp); buf_free(trail); buf_free(ttedigest); return (err); }
void read_aobpcm(AOBPCMDecoder* decoder, struct bs_buffer* packet, array_ia* framelist) { const static uint8_t AOB_BYTE_SWAP[2][6][36] = { { /*16 bps*/ {1, 0, 3, 2}, /*1 ch*/ {1, 0, 3, 2, 5, 4, 7, 6}, /*2 ch*/ {1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10}, /*3 ch*/ { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 }, /*4 ch*/ { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17, 16, 19, 18 }, /*5 ch*/ { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17, 16, 19, 18, 21, 20, 23, 22 } /*6 ch*/ }, { /*24 bps*/ { 2, 1, 5, 4, 0, 3}, /*1 ch*/ { 2, 1, 5, 4, 8, 7, 11, 10, 0, 3, 6, 9 }, /*2 ch*/ { 8, 7, 17, 16, 6, 15, 2, 1, 5, 4, 11, 10, 14, 13, 0, 3, 9, 12 }, /*3 ch*/ { 8, 7, 11, 10, 20, 19, 23, 22, 6, 9, 18, 21, 2, 1, 5, 4, 14, 13, 17, 16, 0, 3, 12, 15 }, /*4 ch*/ { 8, 7, 11, 10, 14, 13, 23, 22, 26, 25, 29, 28, 6, 9, 12, 21, 24, 27, 2, 1, 5, 4, 17, 16, 20, 19, 0, 3, 15, 18 }, /*5 ch*/ { 8, 7, 11, 10, 26, 25, 29, 28, 6, 9, 24, 27, 2, 1, 5, 4, 14, 13, 17, 16, 20, 19, 23, 22, 32, 31, 35, 34, 0, 3, 12, 15, 18, 21, 30, 33 } /*6 ch*/ } }; const unsigned bps = decoder->bps; const unsigned channels = decoder->channels; const unsigned chunk_size = decoder->chunk_size; const unsigned bytes_per_sample = decoder->bytes_per_sample; unsigned i; assert(framelist->len == channels); while ((packet->buffer_size - packet->buffer_position) >= chunk_size) { uint8_t unswapped[36]; uint8_t* unswapped_ptr = unswapped; /*swap read bytes to proper order*/ for (i = 0; i < chunk_size; i++) { unswapped[AOB_BYTE_SWAP[bps][channels - 1][i]] = (uint8_t)buf_getc(packet); } /*decode bytes to PCM ints and place them in proper channels*/ for (i = 0; i < (channels * 2); i++) { array_i* channel = framelist->_[i % channels]; channel->append(channel, decoder->converter(unswapped_ptr)); unswapped_ptr += bytes_per_sample; } } }
packet_t *packet_read(packet_state_t *state) { jint t = buf_getc(state); if (t < 0) return 0; unsigned type = t; state->p.type = type; struct packet_format_desc *fmt; if (type >= MAX_PACKET_FORMAT || !(fmt = &packet_format[t])->known) { #if DEBUG_PROTOCOL >= 1 log_print("IMMINENT CRASH, reading tail for log"); unsigned char buf[256]; for (int i = 0; i < sizeof buf; i++) buf[i] = buf_getc(state); for (int i = 0; i < sizeof buf; i+=16) log_print("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", buf[i+0],buf[i+1],buf[i+2],buf[i+3],buf[i+4],buf[i+5],buf[i+6],buf[i+7], buf[i+8],buf[i+9],buf[i+10],buf[i+11],buf[i+12],buf[i+13],buf[i+14],buf[i+15]); #endif dief("Unknown packet id: 0x%02x", type); } state->p.field_offset = state->offset; for (unsigned f = 0; f < fmt->nfields; f++) { state->p.field_offset[f] = state->buf_pos - state->buf_start; switch (fmt->ftype[f]) { case FIELD_BYTE: case FIELD_UBYTE: if (!buf_skip(state, 1)) return 0; break; case FIELD_SHORT: if (!buf_skip(state, 2)) return 0; break; case FIELD_INT: case FIELD_FLOAT: if (!buf_skip(state, 4)) return 0; break; case FIELD_LONG: case FIELD_DOUBLE: if (!buf_skip(state, 8)) return 0; break; case FIELD_STRING: t = buf_get_jshort(state); if (!buf_skip(state, t*2)) return 0; break; case FIELD_ITEM: if (!buf_skip_item(state)) return 0; break; case FIELD_BYTE_ARRAY: t = buf_get_jint(state); if (!buf_skip(state, t)) return 0; break; case FIELD_BLOCK_ARRAY: t = buf_get_jshort(state); if (!buf_skip(state, 4*t)) return 0; break; case FIELD_ITEM_ARRAY: t = buf_get_jshort(state); for (int i = 0; i < t; i++) if (!buf_skip_item(state)) return 0; break; case FIELD_EXPLOSION_ARRAY: t = buf_get_jint(state); // FIXME: Possible over/underflow? if (!buf_skip(state, 3*t)) return 0; break; case FIELD_MAP_ARRAY: t = buf_getc(state); // Note: Unsigned if (!buf_skip(state, t)) return 0; break; case FIELD_ENTITY_DATA: while (1) { t = buf_getc(state); if (t == 127) break; switch (t >> 5) { case 0: if (!buf_skip(state, 1)) return 0; break; case 1: if (!buf_skip(state, 2)) return 0; break; case 2: case 3: if (!buf_skip(state, 4)) return 0; break; case 4: t = buf_get_jshort(state); if (!buf_skip(state, t)) return 0; break; case 5: if (!buf_skip(state, 5)) return 0; break; } } break; case FIELD_OBJECT_DATA: t = buf_get_jint(state); if (t > 0) if (!buf_skip(state, 6)) return 0; // Skip 3 short break; } } state->p.field_offset[fmt->nfields] = state->buf_pos - state->buf_start; state->p.size = state->buf_pos - state->buf_start; state->p.bytes = &state->buf[state->buf_start]; state->buf_start = state->buf_pos; return &state->p; }
static void rcsclean_file(char *fname, const char *rev_str) { int fd, match; RCSFILE *file; char fpath[PATH_MAX], numb[RCS_REV_BUFSZ]; RCSNUM *rev; BUF *b1, *b2; time_t rcs_mtime = -1; b1 = b2 = NULL; file = NULL; rev = NULL; if ((fd = rcs_choosefile(fname, fpath, sizeof(fpath))) < 0) goto out; if ((file = rcs_open(fpath, fd, RCS_RDWR)) == NULL) goto out; if (flags & PRESERVETIME) rcs_mtime = rcs_get_mtime(file); rcs_kwexp_set(file, kflag); if (rev_str == NULL) rev = file->rf_head; else if ((rev = rcs_getrevnum(rev_str, file)) == NULL) { warnx("%s: Symbolic name `%s' is undefined.", fpath, rev_str); goto out; } if ((b1 = rcs_getrev(file, rev)) == NULL) { warnx("failed to get needed revision"); goto out; } if ((b2 = buf_load(fname)) == NULL) { warnx("failed to load `%s'", fname); goto out; } /* If buffer lengths are the same, compare contents as well. */ if (buf_len(b1) != buf_len(b2)) match = 0; else { size_t len, n; len = buf_len(b1); match = 1; for (n = 0; n < len; ++n) if (buf_getc(b1, n) != buf_getc(b2, n)) { match = 0; break; } } if (match == 1) { if (uflag == 1 && !TAILQ_EMPTY(&(file->rf_locks))) { if (!(flags & QUIET) && nflag == 0) { printf("rcs -u%s %s\n", rcsnum_tostr(rev, numb, sizeof(numb)), fpath); } (void)rcs_lock_remove(file, locker, rev); } if (TAILQ_EMPTY(&(file->rf_locks))) { if (!(flags & QUIET)) printf("rm -f %s\n", fname); if (nflag == 0) (void)unlink(fname); } } rcs_write(file); if (flags & PRESERVETIME) rcs_set_mtime(file, rcs_mtime); out: if (b1 != NULL) buf_free(b1); if (b2 != NULL) buf_free(b2); if (file != NULL) rcs_close(file); }