Fat.cpp revision 9caab76c6b5aefdeeb1715a3695491ca793b8c18
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <fcntl.h> 20#include <unistd.h> 21#include <errno.h> 22#include <string.h> 23#include <dirent.h> 24#include <errno.h> 25#include <fcntl.h> 26 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <sys/types.h> 30#include <sys/mman.h> 31#include <sys/mount.h> 32#include <sys/wait.h> 33#include <linux/fs.h> 34#include <sys/ioctl.h> 35 36#include <linux/kdev_t.h> 37 38#define LOG_TAG "Vold" 39 40#include <cutils/log.h> 41#include <cutils/properties.h> 42 43#include <logwrap/logwrap.h> 44 45#include "Fat.h" 46#include "VoldUtil.h" 47 48static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos"; 49static char MKDOSFS_PATH[] = "/system/bin/newfs_msdos"; 50extern "C" int mount(const char *, const char *, const char *, unsigned long, const void *); 51 52int Fat::check(const char *fsPath) { 53 bool rw = true; 54 if (access(FSCK_MSDOS_PATH, X_OK)) { 55 SLOGW("Skipping fs checks\n"); 56 return 0; 57 } 58 59 int pass = 1; 60 int rc = 0; 61 do { 62 const char *args[4]; 63 int status; 64 args[0] = FSCK_MSDOS_PATH; 65 args[1] = "-p"; 66 args[2] = "-f"; 67 args[3] = fsPath; 68 69 rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, 70 false, true); 71 if (rc != 0) { 72 SLOGE("Filesystem check failed due to logwrap error"); 73 errno = EIO; 74 return -1; 75 } 76 77 if (!WIFEXITED(status)) { 78 SLOGE("Filesystem check did not exit properly"); 79 errno = EIO; 80 return -1; 81 } 82 83 status = WEXITSTATUS(status); 84 85 switch(status) { 86 case 0: 87 SLOGI("Filesystem check completed OK"); 88 return 0; 89 90 case 2: 91 SLOGE("Filesystem check failed (not a FAT filesystem)"); 92 errno = ENODATA; 93 return -1; 94 95 case 4: 96 if (pass++ <= 3) { 97 SLOGW("Filesystem modified - rechecking (pass %d)", 98 pass); 99 continue; 100 } 101 SLOGE("Failing check after too many rechecks"); 102 errno = EIO; 103 return -1; 104 105 default: 106 SLOGE("Filesystem check failed (unknown exit code %d)", status); 107 errno = EIO; 108 return -1; 109 } 110 } while (0); 111 112 return 0; 113} 114 115int Fat::doMount(const char *fsPath, const char *mountPoint, 116 bool ro, bool remount, bool executable, 117 int ownerUid, int ownerGid, int permMask, bool createLost) { 118 int rc; 119 unsigned long flags; 120 char mountData[255]; 121 122 flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC; 123 124 flags |= (executable ? 0 : MS_NOEXEC); 125 flags |= (ro ? MS_RDONLY : 0); 126 flags |= (remount ? MS_REMOUNT : 0); 127 128 /* 129 * Note: This is a temporary hack. If the sampling profiler is enabled, 130 * we make the SD card world-writable so any process can write snapshots. 131 * 132 * TODO: Remove this code once we have a drop box in system_server. 133 */ 134 char value[PROPERTY_VALUE_MAX]; 135 property_get("persist.sampling_profiler", value, ""); 136 if (value[0] == '1') { 137 SLOGW("The SD card is world-writable because the" 138 " 'persist.sampling_profiler' system property is set to '1'."); 139 permMask = 0; 140 } 141 142 sprintf(mountData, 143 "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed", 144 ownerUid, ownerGid, permMask, permMask); 145 146 rc = mount(fsPath, mountPoint, "vfat", flags, mountData); 147 148 if (rc && errno == EROFS) { 149 SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); 150 flags |= MS_RDONLY; 151 rc = mount(fsPath, mountPoint, "vfat", flags, mountData); 152 } 153 154 if (rc == 0 && createLost) { 155 char *lost_path; 156 asprintf(&lost_path, "%s/LOST.DIR", mountPoint); 157 if (access(lost_path, F_OK)) { 158 /* 159 * Create a LOST.DIR in the root so we have somewhere to put 160 * lost cluster chains (fsck_msdos doesn't currently do this) 161 */ 162 if (mkdir(lost_path, 0755)) { 163 SLOGE("Unable to create LOST.DIR (%s)", strerror(errno)); 164 } 165 } 166 free(lost_path); 167 } 168 169 return rc; 170} 171 172int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) { 173 int fd; 174 const char *args[10]; 175 int rc; 176 int status; 177 178 if (wipe) { 179 Fat::wipe(fsPath, numSectors); 180 } 181 182 args[0] = MKDOSFS_PATH; 183 args[1] = "-F"; 184 args[2] = "32"; 185 args[3] = "-O"; 186 args[4] = "android"; 187 args[5] = "-c"; 188 args[6] = "8"; 189 190 if (numSectors) { 191 char tmp[32]; 192 snprintf(tmp, sizeof(tmp), "%u", numSectors); 193 const char *size = tmp; 194 args[7] = "-s"; 195 args[8] = size; 196 args[9] = fsPath; 197 rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, 198 false, true); 199 } else { 200 args[7] = fsPath; 201 rc = android_fork_execvp(8, (char **)args, &status, false, 202 true); 203 } 204 205 if (rc != 0) { 206 SLOGE("Filesystem format failed due to logwrap error"); 207 errno = EIO; 208 return -1; 209 } 210 211 if (!WIFEXITED(status)) { 212 SLOGE("Filesystem format did not exit properly"); 213 errno = EIO; 214 return -1; 215 } 216 217 status = WEXITSTATUS(status); 218 219 if (status == 0) { 220 SLOGI("Filesystem formatted OK"); 221 return 0; 222 } else { 223 SLOGE("Format failed (unknown exit code %d)", status); 224 errno = EIO; 225 return -1; 226 } 227 return 0; 228} 229 230void Fat::wipe(const char *fsPath, unsigned int numSectors) { 231 int fd; 232 unsigned long long range[2]; 233 234 fd = open(fsPath, O_RDWR); 235 if (fd >= 0) { 236 if (numSectors == 0) { 237 numSectors = get_blkdev_size(fd); 238 } 239 if (numSectors == 0) { 240 SLOGE("Fat wipe failed to determine size of %s", fsPath); 241 close(fd); 242 return; 243 } 244 range[0] = 0; 245 range[1] = (unsigned long long)numSectors * 512; 246 if (ioctl(fd, BLKDISCARD, &range) < 0) { 247 SLOGE("Fat wipe failed to discard blocks on %s", fsPath); 248 } else { 249 SLOGI("Fat wipe %d sectors on %s succeeded", numSectors, fsPath); 250 } 251 close(fd); 252 } else { 253 SLOGE("Fat wipe failed to open device %s", fsPath); 254 } 255} 256