+int llog_pack_buffer(int fd, struct llog_log_hdr **llog,
+ struct llog_rec_hdr ***recs,
+ int *recs_number)
+{
+ int rc = 0, recs_num, rd = 0;
+ long long file_size;
+ struct stat st;
+ char *file_buf = NULL, *recs_buf = NULL;
+ struct llog_rec_hdr **recs_pr = NULL;
+ char *ptr = NULL;
+ int i;
+
+ rc = fstat(fd, &st);
+ if (rc < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "Got file stat error.");
+ goto out;
+ }
+
+ file_size = st.st_size;
+ if (file_size < sizeof(**llog)) {
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "File too small for llog header: "
+ "need %zd, size %lld\n",
+ sizeof(**llog), file_size);
+ rc = -EIO;
+ goto out;
+ }
+
+ file_buf = malloc(file_size);
+ if (file_buf == NULL) {
+ rc = -ENOMEM;
+ llapi_error(LLAPI_MSG_ERROR, rc, "Memory Alloc for file_buf.");
+ goto out;
+ }
+ *llog = (struct llog_log_hdr *)file_buf;
+
+ do {
+ rc = read(fd, file_buf + rd, file_size - rd);
+ if (rc > 0)
+ rd += rc;
+ } while (rc > 0 && rd < file_size);
+
+ if (rd < file_size) {
+ rc = rc < 0 ? -errno : -EIO;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "Error reading llog header: need %zd, got %d",
+ sizeof(**llog), rd);
+ goto clear_file_buf;
+ }
+
+ /* the llog header not countable here.*/
+ recs_num = __le32_to_cpu((*llog)->llh_count) - 1;
+
+ recs_buf = malloc(recs_num * sizeof(**recs_pr));
+ if (recs_buf == NULL) {
+ rc = -ENOMEM;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "Error allocating %zd bytes for recs_buf",
+ recs_num * sizeof(**recs_pr));
+ goto clear_file_buf;
+ }
+ recs_pr = (struct llog_rec_hdr **)recs_buf;
+
+ ptr = file_buf + __le32_to_cpu((*llog)->llh_hdr.lrh_len);
+ i = 0;
+
+ while (ptr < (file_buf + file_size)) {
+ struct llog_rec_hdr *cur_rec;
+ int idx;
+ unsigned long offset;
+
+ if (ptr + sizeof(**recs_pr) > file_buf + file_size) {
+ rc = -EINVAL;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "The log is corrupt (too big at %d)", i);
+ goto clear_recs_buf;
+ }
+
+ cur_rec = (struct llog_rec_hdr *)ptr;
+ idx = __le32_to_cpu(cur_rec->lrh_index);
+ recs_pr[i] = cur_rec;
+ offset = (unsigned long)ptr - (unsigned long)file_buf;
+ if (cur_rec->lrh_len == 0 ||
+ cur_rec->lrh_len > (*llog)->llh_hdr.lrh_len) {
+ cur_rec->lrh_len = (*llog)->llh_hdr.lrh_len -
+ offset % (*llog)->llh_hdr.lrh_len;
+ printf("off %lu skip %u to next chunk.\n", offset,
+ cur_rec->lrh_len);
+ i--;
+ } else if (ext2_test_bit(idx, LLOG_HDR_BITMAP(*llog))) {
+ printf("rec #%d type=%x len=%u offset %lu\n", idx,
+ cur_rec->lrh_type, cur_rec->lrh_len, offset);
+ } else {
+ printf("Bit %d of %d not set\n", idx, recs_num);
+ cur_rec->lrh_id = CANCELLED;
+ /* The header counts only set records */
+ i--;
+ }
+
+ ptr += __le32_to_cpu(cur_rec->lrh_len);
+ if ((ptr - file_buf) > file_size) {
+ printf("The log is corrupt (too big at %d)\n", i);
+ rc = -EINVAL;
+ goto clear_recs_buf;
+ }
+ i++;
+ }
+
+ *recs = recs_pr;
+ *recs_number = recs_num;