diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
commit | ffb48f64fec674c6dd923eb8b1eb3f743e05a8ba (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /mtdutils | |
parent | d4ae69739ebb67374d62229829df07bf2de85103 (diff) | |
download | bootable_recovery-ffb48f64fec674c6dd923eb8b1eb3f743e05a8ba.zip bootable_recovery-ffb48f64fec674c6dd923eb8b1eb3f743e05a8ba.tar.gz bootable_recovery-ffb48f64fec674c6dd923eb8b1eb3f743e05a8ba.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'mtdutils')
-rw-r--r-- | mtdutils/Android.mk | 23 | ||||
-rw-r--r-- | mtdutils/flash_image.c | 140 | ||||
-rw-r--r-- | mtdutils/mounts.c | 214 | ||||
-rw-r--r-- | mtdutils/mounts.h | 31 | ||||
-rw-r--r-- | mtdutils/mtdutils.c | 510 | ||||
-rw-r--r-- | mtdutils/mtdutils.h | 54 |
6 files changed, 0 insertions, 972 deletions
diff --git a/mtdutils/Android.mk b/mtdutils/Android.mk deleted file mode 100644 index 1a75423..0000000 --- a/mtdutils/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -ifneq ($(TARGET_SIMULATOR),true) -ifeq ($(TARGET_ARCH),arm) - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - mtdutils.c \ - mounts.c - -LOCAL_MODULE := libmtdutils - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := flash_image.c -LOCAL_MODULE := flash_image -LOCAL_STATIC_LIBRARIES := libmtdutils -LOCAL_SHARED_LIBRARIES := libcutils libc -include $(BUILD_EXECUTABLE) - -endif # TARGET_ARCH == arm -endif # !TARGET_SIMULATOR diff --git a/mtdutils/flash_image.c b/mtdutils/flash_image.c deleted file mode 100644 index c776876..0000000 --- a/mtdutils/flash_image.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "cutils/log.h" -#include "mtdutils.h" - -#define LOG_TAG "flash_image" - -#define HEADER_SIZE 2048 // size of header to compare for equality - -void die(const char *msg, ...) { - int err = errno; - va_list args; - va_start(args, msg); - char buf[1024]; - vsnprintf(buf, sizeof(buf), msg, args); - va_end(args); - - if (err != 0) { - strlcat(buf, ": ", sizeof(buf)); - strlcat(buf, strerror(err), sizeof(buf)); - } - - fprintf(stderr, "%s\n", buf); - LOGE("%s\n", buf); - exit(1); -} - -/* Read an image file and write it to a flash partition. */ - -int main(int argc, char **argv) { - const MtdPartition *ptn; - MtdWriteContext *write; - void *data; - unsigned sz; - - if (argc != 3) { - fprintf(stderr, "usage: %s partition file.img\n", argv[0]); - return 2; - } - - if (mtd_scan_partitions() <= 0) die("error scanning partitions"); - const MtdPartition *partition = mtd_find_partition_by_name(argv[1]); - if (partition == NULL) die("can't find %s partition", argv[1]); - - // If the first part of the file matches the partition, skip writing - - int fd = open(argv[2], O_RDONLY); - if (fd < 0) die("error opening %s", argv[2]); - - char header[HEADER_SIZE]; - int headerlen = read(fd, header, sizeof(header)); - if (headerlen <= 0) die("error reading %s header", argv[2]); - - MtdReadContext *in = mtd_read_partition(partition); - if (in == NULL) { - LOGW("error opening %s: %s\n", argv[1], strerror(errno)); - // just assume it needs re-writing - } else { - char check[HEADER_SIZE]; - int checklen = mtd_read_data(in, check, sizeof(check)); - if (checklen <= 0) { - LOGW("error reading %s: %s\n", argv[1], strerror(errno)); - // just assume it needs re-writing - } else if (checklen == headerlen && !memcmp(header, check, headerlen)) { - LOGI("header is the same, not flashing %s\n", argv[1]); - return 0; - } - mtd_read_close(in); - } - - // Skip the header (we'll come back to it), write everything else - LOGI("flashing %s from %s\n", argv[1], argv[2]); - - MtdWriteContext *out = mtd_write_partition(partition); - if (out == NULL) die("error writing %s", argv[1]); - - char buf[HEADER_SIZE]; - memset(buf, 0, headerlen); - int wrote = mtd_write_data(out, buf, headerlen); - if (wrote != headerlen) die("error writing %s", argv[1]); - - int len; - while ((len = read(fd, buf, sizeof(buf))) > 0) { - wrote = mtd_write_data(out, buf, len); - if (wrote != len) die("error writing %s", argv[1]); - } - if (len < 0) die("error reading %s", argv[2]); - - if (mtd_write_close(out)) die("error closing %s", argv[1]); - - // Now come back and write the header last - - out = mtd_write_partition(partition); - if (out == NULL) die("error re-opening %s", argv[1]); - - wrote = mtd_write_data(out, header, headerlen); - if (wrote != headerlen) die("error re-writing %s", argv[1]); - - // Need to write a complete block, so write the rest of the first block - size_t block_size; - if (mtd_partition_info(partition, NULL, &block_size, NULL)) - die("error getting %s block size", argv[1]); - - if (lseek(fd, headerlen, SEEK_SET) != headerlen) - die("error rewinding %s", argv[2]); - - int left = block_size - headerlen; - while (left < 0) left += block_size; - while (left > 0) { - len = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left); - if (len <= 0) die("error reading %s", argv[2]); - if (mtd_write_data(out, buf, len) != len) - die("error writing %s", argv[1]); - left -= len; - } - - if (mtd_write_close(out)) die("error closing %s", argv[1]); - return 0; -} diff --git a/mtdutils/mounts.c b/mtdutils/mounts.c deleted file mode 100644 index 2ab3ff6..0000000 --- a/mtdutils/mounts.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/mount.h> - -#include "mounts.h" - -struct MountedVolume { - const char *device; - const char *mount_point; - const char *filesystem; - const char *flags; -}; - -typedef struct { - MountedVolume *volumes; - int volumes_allocd; - int volume_count; -} MountsState; - -static MountsState g_mounts_state = { - NULL, // volumes - 0, // volumes_allocd - 0 // volume_count -}; - -static inline void -free_volume_internals(const MountedVolume *volume, int zero) -{ - free((char *)volume->device); - free((char *)volume->mount_point); - free((char *)volume->filesystem); - free((char *)volume->flags); - if (zero) { - memset((void *)volume, 0, sizeof(*volume)); - } -} - -#define PROC_MOUNTS_FILENAME "/proc/mounts" - -int -scan_mounted_volumes() -{ - char buf[2048]; - const char *bufp; - int fd; - ssize_t nbytes; - - if (g_mounts_state.volumes == NULL) { - const int numv = 32; - MountedVolume *volumes = malloc(numv * sizeof(*volumes)); - if (volumes == NULL) { - errno = ENOMEM; - return -1; - } - g_mounts_state.volumes = volumes; - g_mounts_state.volumes_allocd = numv; - memset(volumes, 0, numv * sizeof(*volumes)); - } else { - /* Free the old volume strings. - */ - int i; - for (i = 0; i < g_mounts_state.volume_count; i++) { - free_volume_internals(&g_mounts_state.volumes[i], 1); - } - } - g_mounts_state.volume_count = 0; - - /* Open and read the file contents. - */ - fd = open(PROC_MOUNTS_FILENAME, O_RDONLY); - if (fd < 0) { - goto bail; - } - nbytes = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (nbytes < 0) { - goto bail; - } - buf[nbytes] = '\0'; - - /* Parse the contents of the file, which looks like: - * - * # cat /proc/mounts - * rootfs / rootfs rw 0 0 - * /dev/pts /dev/pts devpts rw 0 0 - * /proc /proc proc rw 0 0 - * /sys /sys sysfs rw 0 0 - * /dev/block/mtdblock4 /system yaffs2 rw,nodev,noatime,nodiratime 0 0 - * /dev/block/mtdblock5 /data yaffs2 rw,nodev,noatime,nodiratime 0 0 - * /dev/block/mmcblk0p1 /sdcard vfat rw,sync,dirsync,fmask=0000,dmask=0000,codepage=cp437,iocharset=iso8859-1,utf8 0 0 - * - * The zeroes at the end are dummy placeholder fields to make the - * output match Linux's /etc/mtab, but don't represent anything here. - */ - bufp = buf; - while (nbytes > 0) { - char device[64]; - char mount_point[64]; - char filesystem[64]; - char flags[128]; - int matches; - - /* %as is a gnu extension that malloc()s a string for each field. - */ - matches = sscanf(bufp, "%63s %63s %63s %127s", - device, mount_point, filesystem, flags); - - if (matches == 4) { - device[sizeof(device)-1] = '\0'; - mount_point[sizeof(mount_point)-1] = '\0'; - filesystem[sizeof(filesystem)-1] = '\0'; - flags[sizeof(flags)-1] = '\0'; - - MountedVolume *v = - &g_mounts_state.volumes[g_mounts_state.volume_count++]; - v->device = strdup(device); - v->mount_point = strdup(mount_point); - v->filesystem = strdup(filesystem); - v->flags = strdup(flags); - } else { -printf("matches was %d on <<%.40s>>\n", matches, bufp); - } - - /* Eat the line. - */ - while (nbytes > 0 && *bufp != '\n') { - bufp++; - nbytes--; - } - if (nbytes > 0) { - bufp++; - nbytes--; - } - } - - return 0; - -bail: -//TODO: free the strings we've allocated. - g_mounts_state.volume_count = 0; - return -1; -} - -const MountedVolume * -find_mounted_volume_by_device(const char *device) -{ - if (g_mounts_state.volumes != NULL) { - int i; - for (i = 0; i < g_mounts_state.volume_count; i++) { - MountedVolume *v = &g_mounts_state.volumes[i]; - /* May be null if it was unmounted and we haven't rescanned. - */ - if (v->device != NULL) { - if (strcmp(v->device, device) == 0) { - return v; - } - } - } - } - return NULL; -} - -const MountedVolume * -find_mounted_volume_by_mount_point(const char *mount_point) -{ - if (g_mounts_state.volumes != NULL) { - int i; - for (i = 0; i < g_mounts_state.volume_count; i++) { - MountedVolume *v = &g_mounts_state.volumes[i]; - /* May be null if it was unmounted and we haven't rescanned. - */ - if (v->mount_point != NULL) { - if (strcmp(v->mount_point, mount_point) == 0) { - return v; - } - } - } - } - return NULL; -} - -int -unmount_mounted_volume(const MountedVolume *volume) -{ - /* Intentionally pass NULL to umount if the caller tries - * to unmount a volume they already unmounted using this - * function. - */ - int ret = umount(volume->mount_point); - if (ret == 0) { - free_volume_internals(volume, 1); - return 0; - } - return ret; -} diff --git a/mtdutils/mounts.h b/mtdutils/mounts.h deleted file mode 100644 index 2e2765a..0000000 --- a/mtdutils/mounts.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef MTDUTILS_MOUNTS_H_ -#define MTDUTILS_MOUNTS_H_ - -typedef struct MountedVolume MountedVolume; - -int scan_mounted_volumes(void); - -const MountedVolume *find_mounted_volume_by_device(const char *device); - -const MountedVolume * -find_mounted_volume_by_mount_point(const char *mount_point); - -int unmount_mounted_volume(const MountedVolume *volume); - -#endif // MTDUTILS_MOUNTS_H_ diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c deleted file mode 100644 index 2b0106f..0000000 --- a/mtdutils/mtdutils.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/mount.h> // for _IOW, _IOR, mount() -#include <sys/stat.h> -#include <mtd/mtd-user.h> -#undef NDEBUG -#include <assert.h> - -#include "mtdutils.h" - -struct MtdPartition { - int device_index; - unsigned int size; - unsigned int erase_size; - char *name; -}; - -struct MtdReadContext { - const MtdPartition *partition; - char *buffer; - size_t consumed; - int fd; -}; - -struct MtdWriteContext { - const MtdPartition *partition; - char *buffer; - size_t stored; - int fd; -}; - -typedef struct { - MtdPartition *partitions; - int partitions_allocd; - int partition_count; -} MtdState; - -static MtdState g_mtd_state = { - NULL, // partitions - 0, // partitions_allocd - -1 // partition_count -}; - -#define MTD_PROC_FILENAME "/proc/mtd" - -int -mtd_scan_partitions() -{ - char buf[2048]; - const char *bufp; - int fd; - int i; - ssize_t nbytes; - - if (g_mtd_state.partitions == NULL) { - const int nump = 32; - MtdPartition *partitions = malloc(nump * sizeof(*partitions)); - if (partitions == NULL) { - errno = ENOMEM; - return -1; - } - g_mtd_state.partitions = partitions; - g_mtd_state.partitions_allocd = nump; - memset(partitions, 0, nump * sizeof(*partitions)); - } - g_mtd_state.partition_count = 0; - - /* Initialize all of the entries to make things easier later. - * (Lets us handle sparsely-numbered partitions, which - * may not even be possible.) - */ - for (i = 0; i < g_mtd_state.partitions_allocd; i++) { - MtdPartition *p = &g_mtd_state.partitions[i]; - if (p->name != NULL) { - free(p->name); - p->name = NULL; - } - p->device_index = -1; - } - - /* Open and read the file contents. - */ - fd = open(MTD_PROC_FILENAME, O_RDONLY); - if (fd < 0) { - goto bail; - } - nbytes = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (nbytes < 0) { - goto bail; - } - buf[nbytes] = '\0'; - - /* Parse the contents of the file, which looks like: - * - * # cat /proc/mtd - * dev: size erasesize name - * mtd0: 00080000 00020000 "bootloader" - * mtd1: 00400000 00020000 "mfg_and_gsm" - * mtd2: 00400000 00020000 "0000000c" - * mtd3: 00200000 00020000 "0000000d" - * mtd4: 04000000 00020000 "system" - * mtd5: 03280000 00020000 "userdata" - */ - bufp = buf; - while (nbytes > 0) { - int mtdnum, mtdsize, mtderasesize; - int matches; - char mtdname[64]; - mtdname[0] = '\0'; - mtdnum = -1; - - matches = sscanf(bufp, "mtd%d: %x %x \"%63[^\"]", - &mtdnum, &mtdsize, &mtderasesize, mtdname); - /* This will fail on the first line, which just contains - * column headers. - */ - if (matches == 4) { - MtdPartition *p = &g_mtd_state.partitions[mtdnum]; - p->device_index = mtdnum; - p->size = mtdsize; - p->erase_size = mtderasesize; - p->name = strdup(mtdname); - if (p->name == NULL) { - errno = ENOMEM; - goto bail; - } - g_mtd_state.partition_count++; - } - - /* Eat the line. - */ - while (nbytes > 0 && *bufp != '\n') { - bufp++; - nbytes--; - } - if (nbytes > 0) { - bufp++; - nbytes--; - } - } - - return g_mtd_state.partition_count; - -bail: - // keep "partitions" around so we can free the names on a rescan. - g_mtd_state.partition_count = -1; - return -1; -} - -const MtdPartition * -mtd_find_partition_by_name(const char *name) -{ - if (g_mtd_state.partitions != NULL) { - int i; - for (i = 0; i < g_mtd_state.partitions_allocd; i++) { - MtdPartition *p = &g_mtd_state.partitions[i]; - if (p->device_index >= 0 && p->name != NULL) { - if (strcmp(p->name, name) == 0) { - return p; - } - } - } - } - return NULL; -} - -int -mtd_mount_partition(const MtdPartition *partition, const char *mount_point, - const char *filesystem, int read_only) -{ - const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME; - char devname[64]; - int rv = -1; - - sprintf(devname, "/dev/block/mtdblock%d", partition->device_index); - if (!read_only) { - rv = mount(devname, mount_point, filesystem, flags, NULL); - } - if (read_only || rv < 0) { - rv = mount(devname, mount_point, filesystem, flags | MS_RDONLY, 0); - if (rv < 0) { - printf("Failed to mount %s on %s: %s\n", - devname, mount_point, strerror(errno)); - } else { - printf("Mount %s on %s read-only\n", devname, mount_point); - } - } -#if 1 //TODO: figure out why this is happening; remove include of stat.h - if (rv >= 0) { - /* For some reason, the x bits sometimes aren't set on the root - * of mounted volumes. - */ - struct stat st; - rv = stat(mount_point, &st); - if (rv < 0) { - return rv; - } - mode_t new_mode = st.st_mode | S_IXUSR | S_IXGRP | S_IXOTH; - if (new_mode != st.st_mode) { -printf("Fixing execute permissions for %s\n", mount_point); - rv = chmod(mount_point, new_mode); - if (rv < 0) { - printf("Couldn't fix permissions for %s: %s\n", - mount_point, strerror(errno)); - } - } - } -#endif - return rv; -} - -int -mtd_partition_info(const MtdPartition *partition, - size_t *total_size, size_t *erase_size, size_t *write_size) -{ - char mtddevname[32]; - sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index); - int fd = open(mtddevname, O_RDONLY); - if (fd < 0) return -1; - - struct mtd_info_user mtd_info; - int ret = ioctl(fd, MEMGETINFO, &mtd_info); - close(fd); - if (ret < 0) return -1; - - if (total_size != NULL) *total_size = mtd_info.size; - if (erase_size != NULL) *erase_size = mtd_info.erasesize; - if (write_size != NULL) *write_size = mtd_info.writesize; - return 0; -} - -MtdReadContext *mtd_read_partition(const MtdPartition *partition) -{ - MtdReadContext *ctx = (MtdReadContext*) malloc(sizeof(MtdReadContext)); - if (ctx == NULL) return NULL; - - ctx->buffer = malloc(partition->erase_size); - if (ctx->buffer == NULL) { - free(ctx); - return NULL; - } - - char mtddevname[32]; - sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index); - ctx->fd = open(mtddevname, O_RDONLY); - if (ctx->fd < 0) { - free(ctx); - free(ctx->buffer); - return NULL; - } - - ctx->partition = partition; - ctx->consumed = partition->erase_size; - return ctx; -} - -static int read_block(const MtdPartition *partition, int fd, char *data) -{ - struct mtd_ecc_stats before, after; - if (ioctl(fd, ECCGETSTATS, &before)) { - fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno)); - return -1; - } - - off_t pos = lseek(fd, 0, SEEK_CUR); - ssize_t size = partition->erase_size; - while (pos + size <= (int) partition->size) { - if (lseek(fd, pos, SEEK_SET) != pos || read(fd, data, size) != size) { - fprintf(stderr, "mtd: read error at 0x%08lx (%s)\n", - pos, strerror(errno)); - } else if (ioctl(fd, ECCGETSTATS, &after)) { - fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno)); - return -1; - } else if (after.failed != before.failed) { - fprintf(stderr, "mtd: ECC errors (%d soft, %d hard) at 0x%08lx\n", - after.corrected - before.corrected, - after.failed - before.failed, pos); - } else { - return 0; // Success! - } - - pos += partition->erase_size; - } - - errno = ENOSPC; - return -1; -} - -ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len) -{ - ssize_t read = 0; - while (read < (int) len) { - if (ctx->consumed < ctx->partition->erase_size) { - size_t avail = ctx->partition->erase_size - ctx->consumed; - size_t copy = len - read < avail ? len - read : avail; - memcpy(data + read, ctx->buffer + ctx->consumed, copy); - ctx->consumed += copy; - read += copy; - } - - // Read complete blocks directly into the user's buffer - while (ctx->consumed == ctx->partition->erase_size && - len - read >= ctx->partition->erase_size) { - if (read_block(ctx->partition, ctx->fd, data + read)) return -1; - read += ctx->partition->erase_size; - } - - // Read the next block into the buffer - if (ctx->consumed == ctx->partition->erase_size && read < (int) len) { - if (read_block(ctx->partition, ctx->fd, ctx->buffer)) return -1; - ctx->consumed = 0; - } - } - - return read; -} - -void mtd_read_close(MtdReadContext *ctx) -{ - close(ctx->fd); - free(ctx->buffer); - free(ctx); -} - -MtdWriteContext *mtd_write_partition(const MtdPartition *partition) -{ - MtdWriteContext *ctx = (MtdWriteContext*) malloc(sizeof(MtdWriteContext)); - if (ctx == NULL) return NULL; - - ctx->buffer = malloc(partition->erase_size); - if (ctx->buffer == NULL) { - free(ctx); - return NULL; - } - - char mtddevname[32]; - sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index); - ctx->fd = open(mtddevname, O_RDWR); - if (ctx->fd < 0) { - free(ctx->buffer); - free(ctx); - return NULL; - } - - ctx->partition = partition; - ctx->stored = 0; - return ctx; -} - -static int write_block(const MtdPartition *partition, int fd, const char *data) -{ - off_t pos = lseek(fd, 0, SEEK_CUR); - if (pos == (off_t) -1) return 1; - - ssize_t size = partition->erase_size; - while (pos + size <= (int) partition->size) { - loff_t bpos = pos; - if (ioctl(fd, MEMGETBADBLOCK, &bpos) > 0) { - fprintf(stderr, "mtd: not writing bad block at 0x%08lx\n", pos); - pos += partition->erase_size; - continue; // Don't try to erase known factory-bad blocks. - } - - struct erase_info_user erase_info; - erase_info.start = pos; - erase_info.length = size; - int retry; - for (retry = 0; retry < 2; ++retry) { - if (ioctl(fd, MEMERASE, &erase_info) < 0) { - fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", - pos, strerror(errno)); - continue; - } - if (lseek(fd, pos, SEEK_SET) != pos || - write(fd, data, size) != size) { - fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n", - pos, strerror(errno)); - } - - char verify[size]; - if (lseek(fd, pos, SEEK_SET) != pos || - read(fd, verify, size) != size) { - fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n", - pos, strerror(errno)); - continue; - } - if (memcmp(data, verify, size) != 0) { - fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n", - pos, strerror(errno)); - continue; - } - - if (retry > 0) { - fprintf(stderr, "mtd: wrote block after %d retries\n", retry); - } - return 0; // Success! - } - - // Try to erase it once more as we give up on this block - fprintf(stderr, "mtd: skipping write block at 0x%08lx\n", pos); - ioctl(fd, MEMERASE, &erase_info); - pos += partition->erase_size; - } - - // Ran out of space on the device - errno = ENOSPC; - return -1; -} - -ssize_t mtd_write_data(MtdWriteContext *ctx, const char *data, size_t len) -{ - size_t wrote = 0; - while (wrote < len) { - // Coalesce partial writes into complete blocks - if (ctx->stored > 0 || len - wrote < ctx->partition->erase_size) { - size_t avail = ctx->partition->erase_size - ctx->stored; - size_t copy = len - wrote < avail ? len - wrote : avail; - memcpy(ctx->buffer + ctx->stored, data + wrote, copy); - ctx->stored += copy; - wrote += copy; - } - - // If a complete block was accumulated, write it - if (ctx->stored == ctx->partition->erase_size) { - if (write_block(ctx->partition, ctx->fd, ctx->buffer)) return -1; - ctx->stored = 0; - } - - // Write complete blocks directly from the user's buffer - while (ctx->stored == 0 && len - wrote >= ctx->partition->erase_size) { - if (write_block(ctx->partition, ctx->fd, data + wrote)) return -1; - wrote += ctx->partition->erase_size; - } - } - - return wrote; -} - -off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) -{ - // Zero-pad and write any pending data to get us to a block boundary - if (ctx->stored > 0) { - size_t zero = ctx->partition->erase_size - ctx->stored; - memset(ctx->buffer + ctx->stored, 0, zero); - if (write_block(ctx->partition, ctx->fd, ctx->buffer)) return -1; - ctx->stored = 0; - } - - off_t pos = lseek(ctx->fd, 0, SEEK_CUR); - if ((off_t) pos == (off_t) -1) return pos; - - const int total = (ctx->partition->size - pos) / ctx->partition->erase_size; - if (blocks < 0) blocks = total; - if (blocks > total) { - errno = ENOSPC; - return -1; - } - - // Erase the specified number of blocks - while (blocks-- > 0) { - loff_t bpos = pos; - if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) { - fprintf(stderr, "mtd: not erasing bad block at 0x%08lx\n", pos); - pos += ctx->partition->erase_size; - continue; // Don't try to erase known factory-bad blocks. - } - - struct erase_info_user erase_info; - erase_info.start = pos; - erase_info.length = ctx->partition->erase_size; - if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) { - fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos); - } - pos += ctx->partition->erase_size; - } - - return pos; -} - -int mtd_write_close(MtdWriteContext *ctx) -{ - int r = 0; - // Make sure any pending data gets written - if (mtd_erase_blocks(ctx, 0) == (off_t) -1) r = -1; - if (close(ctx->fd)) r = -1; - free(ctx->buffer); - free(ctx); - return r; -} diff --git a/mtdutils/mtdutils.h b/mtdutils/mtdutils.h deleted file mode 100644 index 8d2cb56..0000000 --- a/mtdutils/mtdutils.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef MTDUTILS_H_ -#define MTDUTILS_H_ - -#include <sys/types.h> // for size_t, etc. - -typedef struct MtdPartition MtdPartition; - -int mtd_scan_partitions(void); - -const MtdPartition *mtd_find_partition_by_name(const char *name); - -/* mount_point is like "/system" - * filesystem is like "yaffs2" - */ -int mtd_mount_partition(const MtdPartition *partition, const char *mount_point, - const char *filesystem, int read_only); - -/* get the partition and the minimum erase/write block size. NULL is ok. - */ -int mtd_partition_info(const MtdPartition *partition, - size_t *total_size, size_t *erase_size, size_t *write_size); - -/* read or write raw data from a partition, starting at the beginning. - * skips bad blocks as best we can. - */ -typedef struct MtdReadContext MtdReadContext; -typedef struct MtdWriteContext MtdWriteContext; - -MtdReadContext *mtd_read_partition(const MtdPartition *); -ssize_t mtd_read_data(MtdReadContext *, char *data, size_t data_len); -void mtd_read_close(MtdReadContext *); - -MtdWriteContext *mtd_write_partition(const MtdPartition *); -ssize_t mtd_write_data(MtdWriteContext *, const char *data, size_t data_len); -off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */ -int mtd_write_close(MtdWriteContext *); - -#endif // MTDUTILS_H_ |