Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
f1adc05e | 2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4 LT |
3 | * Licensed under the GPL |
4 | */ | |
5 | ||
1da177e4 | 6 | #include <stdio.h> |
84b3db04 JD |
7 | #include <stddef.h> |
8 | #include <unistd.h> | |
1da177e4 LT |
9 | #include <dirent.h> |
10 | #include <errno.h> | |
84b3db04 | 11 | #include <fcntl.h> |
1da177e4 LT |
12 | #include <string.h> |
13 | #include <sys/stat.h> | |
14 | #include <sys/time.h> | |
84b3db04 | 15 | #include <sys/types.h> |
1da177e4 | 16 | #include <sys/vfs.h> |
9a423bb6 | 17 | #include <sys/syscall.h> |
1da177e4 | 18 | #include "hostfs.h" |
84b3db04 | 19 | #include <utime.h> |
1da177e4 | 20 | |
0bc754d1 | 21 | static void statx_to_hostfs(const struct statx *buf, struct hostfs_stat *p) |
39b743c6 | 22 | { |
0bc754d1 BB |
23 | p->ino = buf->stx_ino; |
24 | p->mode = buf->stx_mode; | |
25 | p->nlink = buf->stx_nlink; | |
26 | p->uid = buf->stx_uid; | |
27 | p->gid = buf->stx_gid; | |
28 | p->size = buf->stx_size; | |
29 | p->atime.tv_sec = buf->stx_atime.tv_sec; | |
30 | p->atime.tv_nsec = buf->stx_atime.tv_nsec; | |
31 | p->ctime.tv_sec = buf->stx_ctime.tv_sec; | |
32 | p->ctime.tv_nsec = buf->stx_ctime.tv_nsec; | |
33 | p->mtime.tv_sec = buf->stx_mtime.tv_sec; | |
34 | p->mtime.tv_nsec = buf->stx_mtime.tv_nsec; | |
35 | if (buf->stx_mask & STATX_BTIME) { | |
36 | p->btime.tv_sec = buf->stx_btime.tv_sec; | |
37 | p->btime.tv_nsec = buf->stx_btime.tv_nsec; | |
38 | } else { | |
39 | memset(&p->btime, 0, sizeof(p->btime)); | |
40 | } | |
41 | p->blksize = buf->stx_blksize; | |
42 | p->blocks = buf->stx_blocks; | |
43 | p->rdev.maj = buf->stx_rdev_major; | |
44 | p->rdev.min = buf->stx_rdev_minor; | |
45 | p->dev.maj = buf->stx_dev_major; | |
46 | p->dev.min = buf->stx_dev_minor; | |
39b743c6 AV |
47 | } |
48 | ||
49 | int stat_file(const char *path, struct hostfs_stat *p, int fd) | |
1da177e4 | 50 | { |
0bc754d1 BB |
51 | struct statx buf; |
52 | int flags = AT_SYMLINK_NOFOLLOW; | |
1da177e4 | 53 | |
84b3db04 | 54 | if (fd >= 0) { |
0bc754d1 BB |
55 | flags |= AT_EMPTY_PATH; |
56 | path = ""; | |
5822b7fa | 57 | } |
0bc754d1 BB |
58 | |
59 | if ((statx(fd, path, flags, STATX_BASIC_STATS | STATX_BTIME, &buf)) < 0) | |
60 | return -errno; | |
61 | ||
62 | statx_to_hostfs(&buf, p); | |
f1adc05e | 63 | return 0; |
1da177e4 LT |
64 | } |
65 | ||
1da177e4 LT |
66 | int access_file(char *path, int r, int w, int x) |
67 | { | |
68 | int mode = 0; | |
69 | ||
84b3db04 JD |
70 | if (r) |
71 | mode = R_OK; | |
72 | if (w) | |
73 | mode |= W_OK; | |
74 | if (x) | |
75 | mode |= X_OK; | |
76 | if (access(path, mode) != 0) | |
f1adc05e JD |
77 | return -errno; |
78 | else return 0; | |
1da177e4 LT |
79 | } |
80 | ||
81 | int open_file(char *path, int r, int w, int append) | |
82 | { | |
83 | int mode = 0, fd; | |
84 | ||
84b3db04 | 85 | if (r && !w) |
1da177e4 | 86 | mode = O_RDONLY; |
84b3db04 | 87 | else if (!r && w) |
1da177e4 | 88 | mode = O_WRONLY; |
84b3db04 | 89 | else if (r && w) |
1da177e4 LT |
90 | mode = O_RDWR; |
91 | else panic("Impossible mode in open_file"); | |
92 | ||
84b3db04 | 93 | if (append) |
1da177e4 LT |
94 | mode |= O_APPEND; |
95 | fd = open64(path, mode); | |
84b3db04 | 96 | if (fd < 0) |
f1adc05e JD |
97 | return -errno; |
98 | else return fd; | |
1da177e4 LT |
99 | } |
100 | ||
101 | void *open_dir(char *path, int *err_out) | |
102 | { | |
103 | DIR *dir; | |
104 | ||
105 | dir = opendir(path); | |
106 | *err_out = errno; | |
c5c6dd4e | 107 | |
f1adc05e | 108 | return dir; |
1da177e4 LT |
109 | } |
110 | ||
0c9bd636 RW |
111 | void seek_dir(void *stream, unsigned long long pos) |
112 | { | |
113 | DIR *dir = stream; | |
114 | ||
115 | seekdir(dir, pos); | |
116 | } | |
117 | ||
118 | char *read_dir(void *stream, unsigned long long *pos_out, | |
3ee6bd8e GU |
119 | unsigned long long *ino_out, int *len_out, |
120 | unsigned int *type_out) | |
1da177e4 LT |
121 | { |
122 | DIR *dir = stream; | |
123 | struct dirent *ent; | |
124 | ||
1da177e4 | 125 | ent = readdir(dir); |
84b3db04 | 126 | if (ent == NULL) |
f1adc05e | 127 | return NULL; |
1da177e4 LT |
128 | *len_out = strlen(ent->d_name); |
129 | *ino_out = ent->d_ino; | |
3ee6bd8e | 130 | *type_out = ent->d_type; |
0c9bd636 | 131 | *pos_out = ent->d_off; |
f1adc05e | 132 | return ent->d_name; |
1da177e4 LT |
133 | } |
134 | ||
135 | int read_file(int fd, unsigned long long *offset, char *buf, int len) | |
136 | { | |
137 | int n; | |
138 | ||
139 | n = pread64(fd, buf, len, *offset); | |
84b3db04 | 140 | if (n < 0) |
f1adc05e | 141 | return -errno; |
1da177e4 | 142 | *offset += n; |
f1adc05e | 143 | return n; |
1da177e4 LT |
144 | } |
145 | ||
146 | int write_file(int fd, unsigned long long *offset, const char *buf, int len) | |
147 | { | |
148 | int n; | |
149 | ||
150 | n = pwrite64(fd, buf, len, *offset); | |
84b3db04 | 151 | if (n < 0) |
f1adc05e | 152 | return -errno; |
1da177e4 | 153 | *offset += n; |
f1adc05e | 154 | return n; |
1da177e4 LT |
155 | } |
156 | ||
157 | int lseek_file(int fd, long long offset, int whence) | |
158 | { | |
159 | int ret; | |
160 | ||
161 | ret = lseek64(fd, offset, whence); | |
84b3db04 | 162 | if (ret < 0) |
f1adc05e JD |
163 | return -errno; |
164 | return 0; | |
1da177e4 LT |
165 | } |
166 | ||
a2d76bd8 PBG |
167 | int fsync_file(int fd, int datasync) |
168 | { | |
169 | int ret; | |
170 | if (datasync) | |
171 | ret = fdatasync(fd); | |
172 | else | |
173 | ret = fsync(fd); | |
174 | ||
175 | if (ret < 0) | |
176 | return -errno; | |
177 | return 0; | |
178 | } | |
179 | ||
f8ad850f AV |
180 | int replace_file(int oldfd, int fd) |
181 | { | |
182 | return dup2(oldfd, fd); | |
183 | } | |
184 | ||
1da177e4 LT |
185 | void close_file(void *stream) |
186 | { | |
187 | close(*((int *) stream)); | |
188 | } | |
189 | ||
190 | void close_dir(void *stream) | |
191 | { | |
192 | closedir(stream); | |
193 | } | |
194 | ||
b98b9102 | 195 | int file_create(char *name, int mode) |
1da177e4 | 196 | { |
b98b9102 RW |
197 | int fd; |
198 | ||
1da177e4 | 199 | fd = open64(name, O_CREAT | O_RDWR, mode); |
84b3db04 | 200 | if (fd < 0) |
f1adc05e JD |
201 | return -errno; |
202 | return fd; | |
1da177e4 LT |
203 | } |
204 | ||
5822b7fa | 205 | int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) |
1da177e4 | 206 | { |
39b743c6 | 207 | struct hostfs_stat st; |
5822b7fa | 208 | struct timeval times[2]; |
1da177e4 LT |
209 | int err, ma; |
210 | ||
5822b7fa AB |
211 | if (attrs->ia_valid & HOSTFS_ATTR_MODE) { |
212 | if (fd >= 0) { | |
213 | if (fchmod(fd, attrs->ia_mode) != 0) | |
c5c6dd4e | 214 | return -errno; |
5822b7fa | 215 | } else if (chmod(file, attrs->ia_mode) != 0) { |
f1adc05e | 216 | return -errno; |
5822b7fa | 217 | } |
1da177e4 | 218 | } |
5822b7fa AB |
219 | if (attrs->ia_valid & HOSTFS_ATTR_UID) { |
220 | if (fd >= 0) { | |
221 | if (fchown(fd, attrs->ia_uid, -1)) | |
f1adc05e | 222 | return -errno; |
84b3db04 | 223 | } else if (chown(file, attrs->ia_uid, -1)) { |
f1adc05e | 224 | return -errno; |
5822b7fa | 225 | } |
1da177e4 | 226 | } |
5822b7fa AB |
227 | if (attrs->ia_valid & HOSTFS_ATTR_GID) { |
228 | if (fd >= 0) { | |
229 | if (fchown(fd, -1, attrs->ia_gid)) | |
f1adc05e | 230 | return -errno; |
5822b7fa | 231 | } else if (chown(file, -1, attrs->ia_gid)) { |
f1adc05e | 232 | return -errno; |
5822b7fa | 233 | } |
1da177e4 | 234 | } |
5822b7fa AB |
235 | if (attrs->ia_valid & HOSTFS_ATTR_SIZE) { |
236 | if (fd >= 0) { | |
237 | if (ftruncate(fd, attrs->ia_size)) | |
f1adc05e | 238 | return -errno; |
5822b7fa | 239 | } else if (truncate(file, attrs->ia_size)) { |
f1adc05e | 240 | return -errno; |
5822b7fa | 241 | } |
1da177e4 | 242 | } |
5822b7fa | 243 | |
84b3db04 JD |
244 | /* |
245 | * Update accessed and/or modified time, in two parts: first set | |
5822b7fa | 246 | * times according to the changes to perform, and then call futimes() |
84b3db04 JD |
247 | * or utimes() to apply them. |
248 | */ | |
5822b7fa AB |
249 | ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET); |
250 | if (attrs->ia_valid & ma) { | |
39b743c6 | 251 | err = stat_file(file, &st, fd); |
5822b7fa AB |
252 | if (err != 0) |
253 | return err; | |
254 | ||
39b743c6 AV |
255 | times[0].tv_sec = st.atime.tv_sec; |
256 | times[0].tv_usec = st.atime.tv_nsec / 1000; | |
257 | times[1].tv_sec = st.mtime.tv_sec; | |
258 | times[1].tv_usec = st.mtime.tv_nsec / 1000; | |
5822b7fa AB |
259 | |
260 | if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) { | |
261 | times[0].tv_sec = attrs->ia_atime.tv_sec; | |
d7b88513 | 262 | times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000; |
1da177e4 | 263 | } |
5822b7fa AB |
264 | if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) { |
265 | times[1].tv_sec = attrs->ia_mtime.tv_sec; | |
d7b88513 | 266 | times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000; |
5822b7fa AB |
267 | } |
268 | ||
269 | if (fd >= 0) { | |
270 | if (futimes(fd, times) != 0) | |
f1adc05e | 271 | return -errno; |
5822b7fa | 272 | } else if (utimes(file, times) != 0) { |
f1adc05e | 273 | return -errno; |
1da177e4 LT |
274 | } |
275 | } | |
5822b7fa | 276 | |
baabd156 | 277 | /* Note: ctime is not handled */ |
84b3db04 | 278 | if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) { |
39b743c6 AV |
279 | err = stat_file(file, &st, fd); |
280 | attrs->ia_atime = st.atime; | |
281 | attrs->ia_mtime = st.mtime; | |
84b3db04 | 282 | if (err != 0) |
f1adc05e | 283 | return err; |
1da177e4 | 284 | } |
f1adc05e | 285 | return 0; |
1da177e4 LT |
286 | } |
287 | ||
288 | int make_symlink(const char *from, const char *to) | |
289 | { | |
290 | int err; | |
291 | ||
292 | err = symlink(to, from); | |
84b3db04 | 293 | if (err) |
f1adc05e JD |
294 | return -errno; |
295 | return 0; | |
1da177e4 LT |
296 | } |
297 | ||
298 | int unlink_file(const char *file) | |
299 | { | |
300 | int err; | |
301 | ||
302 | err = unlink(file); | |
84b3db04 | 303 | if (err) |
f1adc05e JD |
304 | return -errno; |
305 | return 0; | |
1da177e4 LT |
306 | } |
307 | ||
308 | int do_mkdir(const char *file, int mode) | |
309 | { | |
310 | int err; | |
311 | ||
312 | err = mkdir(file, mode); | |
84b3db04 | 313 | if (err) |
f1adc05e JD |
314 | return -errno; |
315 | return 0; | |
1da177e4 LT |
316 | } |
317 | ||
6380161c | 318 | int hostfs_do_rmdir(const char *file) |
1da177e4 LT |
319 | { |
320 | int err; | |
321 | ||
322 | err = rmdir(file); | |
84b3db04 | 323 | if (err) |
f1adc05e JD |
324 | return -errno; |
325 | return 0; | |
1da177e4 LT |
326 | } |
327 | ||
88f6cd0c | 328 | int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor) |
1da177e4 LT |
329 | { |
330 | int err; | |
331 | ||
005a59ec | 332 | err = mknod(file, mode, os_makedev(major, minor)); |
84b3db04 | 333 | if (err) |
f1adc05e JD |
334 | return -errno; |
335 | return 0; | |
1da177e4 LT |
336 | } |
337 | ||
338 | int link_file(const char *to, const char *from) | |
339 | { | |
340 | int err; | |
341 | ||
342 | err = link(to, from); | |
84b3db04 | 343 | if (err) |
f1adc05e JD |
344 | return -errno; |
345 | return 0; | |
1da177e4 LT |
346 | } |
347 | ||
ea7e743e | 348 | int hostfs_do_readlink(char *file, char *buf, int size) |
1da177e4 LT |
349 | { |
350 | int n; | |
351 | ||
352 | n = readlink(file, buf, size); | |
84b3db04 | 353 | if (n < 0) |
f1adc05e | 354 | return -errno; |
84b3db04 | 355 | if (n < size) |
1da177e4 | 356 | buf[n] = '\0'; |
f1adc05e | 357 | return n; |
1da177e4 LT |
358 | } |
359 | ||
360 | int rename_file(char *from, char *to) | |
361 | { | |
362 | int err; | |
363 | ||
364 | err = rename(from, to); | |
84b3db04 | 365 | if (err < 0) |
f1adc05e JD |
366 | return -errno; |
367 | return 0; | |
1da177e4 LT |
368 | } |
369 | ||
9a423bb6 MS |
370 | int rename2_file(char *from, char *to, unsigned int flags) |
371 | { | |
372 | int err; | |
373 | ||
374 | #ifndef SYS_renameat2 | |
375 | # ifdef __x86_64__ | |
376 | # define SYS_renameat2 316 | |
377 | # endif | |
378 | # ifdef __i386__ | |
379 | # define SYS_renameat2 353 | |
380 | # endif | |
381 | #endif | |
382 | ||
383 | #ifdef SYS_renameat2 | |
384 | err = syscall(SYS_renameat2, AT_FDCWD, from, AT_FDCWD, to, flags); | |
385 | if (err < 0) { | |
386 | if (errno != ENOSYS) | |
387 | return -errno; | |
388 | else | |
389 | return -EINVAL; | |
390 | } | |
391 | return 0; | |
392 | #else | |
393 | return -EINVAL; | |
394 | #endif | |
395 | } | |
396 | ||
1da177e4 LT |
397 | int do_statfs(char *root, long *bsize_out, long long *blocks_out, |
398 | long long *bfree_out, long long *bavail_out, | |
399 | long long *files_out, long long *ffree_out, | |
1b627d57 | 400 | void *fsid_out, int fsid_size, long *namelen_out) |
1da177e4 LT |
401 | { |
402 | struct statfs64 buf; | |
403 | int err; | |
404 | ||
405 | err = statfs64(root, &buf); | |
84b3db04 | 406 | if (err < 0) |
f1adc05e JD |
407 | return -errno; |
408 | ||
1da177e4 LT |
409 | *bsize_out = buf.f_bsize; |
410 | *blocks_out = buf.f_blocks; | |
411 | *bfree_out = buf.f_bfree; | |
412 | *bavail_out = buf.f_bavail; | |
413 | *files_out = buf.f_files; | |
414 | *ffree_out = buf.f_ffree; | |
415 | memcpy(fsid_out, &buf.f_fsid, | |
416 | sizeof(buf.f_fsid) > fsid_size ? fsid_size : | |
417 | sizeof(buf.f_fsid)); | |
418 | *namelen_out = buf.f_namelen; | |
1b627d57 | 419 | |
f1adc05e | 420 | return 0; |
1da177e4 | 421 | } |