1 /* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <stdio.h> 7 #include <stddef.h> 8 #include <unistd.h> 9 #include <dirent.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <string.h> 13 #include <sys/stat.h> 14 #include <sys/time.h> 15 #include <sys/types.h> 16 #include <sys/vfs.h> 17 #include "hostfs.h" 18 #include "os.h" 19 #include "user.h" 20 #include <utime.h> 21 22 int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, 23 int *nlink_out, int *uid_out, int *gid_out, 24 unsigned long long *size_out, struct timespec *atime_out, 25 struct timespec *mtime_out, struct timespec *ctime_out, 26 int *blksize_out, unsigned long long *blocks_out, int fd) 27 { 28 struct stat64 buf; 29 30 if (fd >= 0) { 31 if (fstat64(fd, &buf) < 0) 32 return -errno; 33 } else if (lstat64(path, &buf) < 0) { 34 return -errno; 35 } 36 37 if (inode_out != NULL) 38 *inode_out = buf.st_ino; 39 if (mode_out != NULL) 40 *mode_out = buf.st_mode; 41 if (nlink_out != NULL) 42 *nlink_out = buf.st_nlink; 43 if (uid_out != NULL) 44 *uid_out = buf.st_uid; 45 if (gid_out != NULL) 46 *gid_out = buf.st_gid; 47 if (size_out != NULL) 48 *size_out = buf.st_size; 49 if (atime_out != NULL) { 50 atime_out->tv_sec = buf.st_atime; 51 atime_out->tv_nsec = 0; 52 } 53 if (mtime_out != NULL) { 54 mtime_out->tv_sec = buf.st_mtime; 55 mtime_out->tv_nsec = 0; 56 } 57 if (ctime_out != NULL) { 58 ctime_out->tv_sec = buf.st_ctime; 59 ctime_out->tv_nsec = 0; 60 } 61 if (blksize_out != NULL) 62 *blksize_out = buf.st_blksize; 63 if (blocks_out != NULL) 64 *blocks_out = buf.st_blocks; 65 return 0; 66 } 67 68 int file_type(const char *path, int *maj, int *min) 69 { 70 struct stat64 buf; 71 72 if (lstat64(path, &buf) < 0) 73 return -errno; 74 /* 75 * We cannot pass rdev as is because glibc and the kernel disagree 76 * about its definition. 77 */ 78 if (maj != NULL) 79 *maj = major(buf.st_rdev); 80 if (min != NULL) 81 *min = minor(buf.st_rdev); 82 83 if (S_ISDIR(buf.st_mode)) 84 return OS_TYPE_DIR; 85 else if (S_ISLNK(buf.st_mode)) 86 return OS_TYPE_SYMLINK; 87 else if (S_ISCHR(buf.st_mode)) 88 return OS_TYPE_CHARDEV; 89 else if (S_ISBLK(buf.st_mode)) 90 return OS_TYPE_BLOCKDEV; 91 else if (S_ISFIFO(buf.st_mode)) 92 return OS_TYPE_FIFO; 93 else if (S_ISSOCK(buf.st_mode)) 94 return OS_TYPE_SOCK; 95 else return OS_TYPE_FILE; 96 } 97 98 int access_file(char *path, int r, int w, int x) 99 { 100 int mode = 0; 101 102 if (r) 103 mode = R_OK; 104 if (w) 105 mode |= W_OK; 106 if (x) 107 mode |= X_OK; 108 if (access(path, mode) != 0) 109 return -errno; 110 else return 0; 111 } 112 113 int open_file(char *path, int r, int w, int append) 114 { 115 int mode = 0, fd; 116 117 if (r && !w) 118 mode = O_RDONLY; 119 else if (!r && w) 120 mode = O_WRONLY; 121 else if (r && w) 122 mode = O_RDWR; 123 else panic("Impossible mode in open_file"); 124 125 if (append) 126 mode |= O_APPEND; 127 fd = open64(path, mode); 128 if (fd < 0) 129 return -errno; 130 else return fd; 131 } 132 133 void *open_dir(char *path, int *err_out) 134 { 135 DIR *dir; 136 137 dir = opendir(path); 138 *err_out = errno; 139 if (dir == NULL) 140 return NULL; 141 return dir; 142 } 143 144 char *read_dir(void *stream, unsigned long long *pos, 145 unsigned long long *ino_out, int *len_out) 146 { 147 DIR *dir = stream; 148 struct dirent *ent; 149 150 seekdir(dir, *pos); 151 ent = readdir(dir); 152 if (ent == NULL) 153 return NULL; 154 *len_out = strlen(ent->d_name); 155 *ino_out = ent->d_ino; 156 *pos = telldir(dir); 157 return ent->d_name; 158 } 159 160 int read_file(int fd, unsigned long long *offset, char *buf, int len) 161 { 162 int n; 163 164 n = pread64(fd, buf, len, *offset); 165 if (n < 0) 166 return -errno; 167 *offset += n; 168 return n; 169 } 170 171 int write_file(int fd, unsigned long long *offset, const char *buf, int len) 172 { 173 int n; 174 175 n = pwrite64(fd, buf, len, *offset); 176 if (n < 0) 177 return -errno; 178 *offset += n; 179 return n; 180 } 181 182 int lseek_file(int fd, long long offset, int whence) 183 { 184 int ret; 185 186 ret = lseek64(fd, offset, whence); 187 if (ret < 0) 188 return -errno; 189 return 0; 190 } 191 192 int fsync_file(int fd, int datasync) 193 { 194 int ret; 195 if (datasync) 196 ret = fdatasync(fd); 197 else 198 ret = fsync(fd); 199 200 if (ret < 0) 201 return -errno; 202 return 0; 203 } 204 205 void close_file(void *stream) 206 { 207 close(*((int *) stream)); 208 } 209 210 void close_dir(void *stream) 211 { 212 closedir(stream); 213 } 214 215 int file_create(char *name, int ur, int uw, int ux, int gr, 216 int gw, int gx, int or, int ow, int ox) 217 { 218 int mode, fd; 219 220 mode = 0; 221 mode |= ur ? S_IRUSR : 0; 222 mode |= uw ? S_IWUSR : 0; 223 mode |= ux ? S_IXUSR : 0; 224 mode |= gr ? S_IRGRP : 0; 225 mode |= gw ? S_IWGRP : 0; 226 mode |= gx ? S_IXGRP : 0; 227 mode |= or ? S_IROTH : 0; 228 mode |= ow ? S_IWOTH : 0; 229 mode |= ox ? S_IXOTH : 0; 230 fd = open64(name, O_CREAT | O_RDWR, mode); 231 if (fd < 0) 232 return -errno; 233 return fd; 234 } 235 236 int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) 237 { 238 struct timeval times[2]; 239 struct timespec atime_ts, mtime_ts; 240 int err, ma; 241 242 if (attrs->ia_valid & HOSTFS_ATTR_MODE) { 243 if (fd >= 0) { 244 if (fchmod(fd, attrs->ia_mode) != 0) 245 return (-errno); 246 } else if (chmod(file, attrs->ia_mode) != 0) { 247 return -errno; 248 } 249 } 250 if (attrs->ia_valid & HOSTFS_ATTR_UID) { 251 if (fd >= 0) { 252 if (fchown(fd, attrs->ia_uid, -1)) 253 return -errno; 254 } else if (chown(file, attrs->ia_uid, -1)) { 255 return -errno; 256 } 257 } 258 if (attrs->ia_valid & HOSTFS_ATTR_GID) { 259 if (fd >= 0) { 260 if (fchown(fd, -1, attrs->ia_gid)) 261 return -errno; 262 } else if (chown(file, -1, attrs->ia_gid)) { 263 return -errno; 264 } 265 } 266 if (attrs->ia_valid & HOSTFS_ATTR_SIZE) { 267 if (fd >= 0) { 268 if (ftruncate(fd, attrs->ia_size)) 269 return -errno; 270 } else if (truncate(file, attrs->ia_size)) { 271 return -errno; 272 } 273 } 274 275 /* 276 * Update accessed and/or modified time, in two parts: first set 277 * times according to the changes to perform, and then call futimes() 278 * or utimes() to apply them. 279 */ 280 ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET); 281 if (attrs->ia_valid & ma) { 282 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, 283 &atime_ts, &mtime_ts, NULL, NULL, NULL, fd); 284 if (err != 0) 285 return err; 286 287 times[0].tv_sec = atime_ts.tv_sec; 288 times[0].tv_usec = atime_ts.tv_nsec / 1000; 289 times[1].tv_sec = mtime_ts.tv_sec; 290 times[1].tv_usec = mtime_ts.tv_nsec / 1000; 291 292 if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) { 293 times[0].tv_sec = attrs->ia_atime.tv_sec; 294 times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000; 295 } 296 if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) { 297 times[1].tv_sec = attrs->ia_mtime.tv_sec; 298 times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000; 299 } 300 301 if (fd >= 0) { 302 if (futimes(fd, times) != 0) 303 return -errno; 304 } else if (utimes(file, times) != 0) { 305 return -errno; 306 } 307 } 308 309 /* Note: ctime is not handled */ 310 if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) { 311 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, 312 &attrs->ia_atime, &attrs->ia_mtime, NULL, 313 NULL, NULL, fd); 314 if (err != 0) 315 return err; 316 } 317 return 0; 318 } 319 320 int make_symlink(const char *from, const char *to) 321 { 322 int err; 323 324 err = symlink(to, from); 325 if (err) 326 return -errno; 327 return 0; 328 } 329 330 int unlink_file(const char *file) 331 { 332 int err; 333 334 err = unlink(file); 335 if (err) 336 return -errno; 337 return 0; 338 } 339 340 int do_mkdir(const char *file, int mode) 341 { 342 int err; 343 344 err = mkdir(file, mode); 345 if (err) 346 return -errno; 347 return 0; 348 } 349 350 int do_rmdir(const char *file) 351 { 352 int err; 353 354 err = rmdir(file); 355 if (err) 356 return -errno; 357 return 0; 358 } 359 360 int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor) 361 { 362 int err; 363 364 err = mknod(file, mode, makedev(major, minor)); 365 if (err) 366 return -errno; 367 return 0; 368 } 369 370 int link_file(const char *to, const char *from) 371 { 372 int err; 373 374 err = link(to, from); 375 if (err) 376 return -errno; 377 return 0; 378 } 379 380 int hostfs_do_readlink(char *file, char *buf, int size) 381 { 382 int n; 383 384 n = readlink(file, buf, size); 385 if (n < 0) 386 return -errno; 387 if (n < size) 388 buf[n] = '\0'; 389 return n; 390 } 391 392 int rename_file(char *from, char *to) 393 { 394 int err; 395 396 err = rename(from, to); 397 if (err < 0) 398 return -errno; 399 return 0; 400 } 401 402 int do_statfs(char *root, long *bsize_out, long long *blocks_out, 403 long long *bfree_out, long long *bavail_out, 404 long long *files_out, long long *ffree_out, 405 void *fsid_out, int fsid_size, long *namelen_out, 406 long *spare_out) 407 { 408 struct statfs64 buf; 409 int err; 410 411 err = statfs64(root, &buf); 412 if (err < 0) 413 return -errno; 414 415 *bsize_out = buf.f_bsize; 416 *blocks_out = buf.f_blocks; 417 *bfree_out = buf.f_bfree; 418 *bavail_out = buf.f_bavail; 419 *files_out = buf.f_files; 420 *ffree_out = buf.f_ffree; 421 memcpy(fsid_out, &buf.f_fsid, 422 sizeof(buf.f_fsid) > fsid_size ? fsid_size : 423 sizeof(buf.f_fsid)); 424 *namelen_out = buf.f_namelen; 425 spare_out[0] = buf.f_spare[0]; 426 spare_out[1] = buf.f_spare[1]; 427 spare_out[2] = buf.f_spare[2]; 428 spare_out[3] = buf.f_spare[3]; 429 spare_out[4] = buf.f_spare[4]; 430 return 0; 431 } 432