text: /* libs/diskconfig/diskutils.c
   *
   * Copyright 2008, The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #define LOG_TAG "diskutils"
  
  #include <errno.h>
  #include <fcntl.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <sys/stat.h>
  
  #include <cutils/log.h>
  
  #include <diskconfig/diskconfig.h>
  
  int
  write_raw_image(const char *dst, const char *src, loff_t offset, int test)
  {
      int dst_fd = -1;
      int src_fd = -1;
      uint8_t buffer[4096];
      int buf_offset;
      int nr_bytes;
      int tmp;
      int done = 0;
      uint64_t total = 0;
  
      ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, offset);
      if ((src_fd = open(src, O_RDONLY)) < 0) {
          ALOGE("Could not open %s for reading (errno=%d).", src, errno);
          goto fail;
      }
  
      if (!test) {
          if ((dst_fd = open(dst, O_RDWR)) < 0) {
              ALOGE("Could not open '%s' for read/write (errno=%d).", dst, errno);
              goto fail;
          }
  
          if (lseek64(dst_fd, offset, SEEK_SET) != offset) {
              ALOGE("Could not seek to offset %lld in %s.", offset, dst);
              goto fail;
          }
      }
  
      while (!done) {
          if ((nr_bytes = read(src_fd, buffer, sizeof(buffer))) < 0) {
              /* XXX: Should we not even bother with EINTR? */
              if (errno == EINTR)
                  continue;
              ALOGE("Error (%d) while reading from '%s'", errno, src);
              goto fail;
          }
  
          if (!nr_bytes) {
              /* we're done. */
              done = 1;
              break;
          }
  
          total += nr_bytes;
  
          /* skip the write loop if we're testing */
          if (test)
              nr_bytes = 0;
  
          buf_offset = 0;
          while (nr_bytes > 0) {
              if ((tmp = write(dst_fd, &buffer[buf_offset], nr_bytes)) < 0) {
                  /* XXX: Should we not even bother with EINTR? */
                  if (errno == EINTR)
                      continue;
                  ALOGE("Error (%d) while writing to '%s'", errno, dst);
                  goto fail;
              }
              if (!tmp)
                  continue;
              nr_bytes -= tmp;
              buf_offset += tmp;
          }
      }
  
      if (!done) {
          ALOGE("Exited read/write loop without setting flag! WTF?!");
          goto fail;
      }
  
      if (dst_fd >= 0)
          fsync(dst_fd);
  
      ALOGI("Wrote %llu bytes to %s @ %lld", total, dst, offset);
  
      close(src_fd);
      if (dst_fd >= 0)
          close(dst_fd);
      return 0;
  
  fail:
      if (dst_fd >= 0)
          close(dst_fd);
      if (src_fd >= 0)
          close(src_fd);
      return 1;
  }
  