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