fs.c revision 9685194fc94510a33201aee9b80c23f206ccfe67
1/* 2 * Copyright (C) 2012 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 <cutils/fs.h> 18#include <cutils/log.h> 19 20#include <sys/types.h> 21#include <sys/stat.h> 22#include <fcntl.h> 23#include <unistd.h> 24#include <errno.h> 25#include <string.h> 26#include <limits.h> 27 28#define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) 29#define BUF_SIZE 64 30 31int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) { 32 // Check if path needs to be created 33 struct stat sb; 34 if (lstat(path, &sb) == -1) { 35 if (errno == ENOENT) { 36 goto create; 37 } else { 38 ALOGE("Failed to stat(%s): %s", path, strerror(errno)); 39 return -1; 40 } 41 } 42 43 // Exists, verify status 44 if (!S_ISDIR(sb.st_mode)) { 45 ALOGE("Not a directory: %s", path); 46 return -1; 47 } 48 if (((sb.st_mode & ALL_PERMS) == mode) && (sb.st_uid == uid) && (sb.st_gid == gid)) { 49 return 0; 50 } else { 51 goto fixup; 52 } 53 54create: 55 if (mkdir(path, mode) == -1) { 56 ALOGE("Failed to mkdir(%s): %s", path, strerror(errno)); 57 return -1; 58 } 59 60fixup: 61 if (chmod(path, mode) == -1) { 62 ALOGE("Failed to chown(%s, %d): %s", path, mode, strerror(errno)); 63 return -1; 64 } 65 if (chown(path, uid, gid) == -1) { 66 ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno)); 67 return -1; 68 } 69 70 return 0; 71} 72 73int fs_read_atomic_int(const char* path, int* out_value) { 74 int fd = open(path, O_RDONLY); 75 if (fd == -1) { 76 ALOGE("Failed to read %s: %s", path, strerror(errno)); 77 return -1; 78 } 79 80 char buf[BUF_SIZE]; 81 if (read(fd, buf, BUF_SIZE) == -1) { 82 ALOGE("Failed to read %s: %s", path, strerror(errno)); 83 goto fail; 84 } 85 if (sscanf(buf, "%d", out_value) != 1) { 86 ALOGE("Failed to parse %s: %s", path, strerror(errno)); 87 goto fail; 88 } 89 close(fd); 90 return 0; 91 92fail: 93 close(fd); 94 *out_value = -1; 95 return -1; 96} 97 98int fs_write_atomic_int(const char* path, int value) { 99 char temp[PATH_MAX]; 100 if (snprintf(temp, PATH_MAX, "%s.XXXXXX", path) >= PATH_MAX) { 101 ALOGE("Path too long"); 102 return -1; 103 } 104 105 int fd = mkstemp(temp); 106 if (fd == -1) { 107 ALOGE("Failed to open %s: %s", temp, strerror(errno)); 108 return -1; 109 } 110 111 char buf[BUF_SIZE]; 112 int len = snprintf(buf, BUF_SIZE, "%d", value) + 1; 113 if (len > BUF_SIZE) { 114 ALOGE("Value %d too large: %s", value, strerror(errno)); 115 goto fail; 116 } 117 if (write(fd, buf, len) < len) { 118 ALOGE("Failed to write %s: %s", temp, strerror(errno)); 119 goto fail; 120 } 121 if (close(fd) == -1) { 122 ALOGE("Failed to close %s: %s", temp, strerror(errno)); 123 goto fail_closed; 124 } 125 126 if (rename(temp, path) == -1) { 127 ALOGE("Failed to rename %s to %s: %s", temp, path, strerror(errno)); 128 goto fail_closed; 129 } 130 131 return 0; 132 133fail: 134 close(fd); 135fail_closed: 136 unlink(temp); 137 return -1; 138} 139