blob: 701d454a6791ca001ecc24499cd21be59121f731 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikef1adc052007-05-08 00:23:18 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 */
5
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <stdio.h>
Jeff Dike84b3db02007-10-16 01:27:13 -07007#include <stddef.h>
8#include <unistd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <dirent.h>
10#include <errno.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070011#include <fcntl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <string.h>
13#include <sys/stat.h>
14#include <sys/time.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070015#include <sys/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <sys/vfs.h>
17#include "hostfs.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070018#include "os.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "user.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070020#include <utime.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Al Viro39b743c2010-06-06 20:08:56 -040022static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
23{
24 p->ino = buf->st_ino;
25 p->mode = buf->st_mode;
26 p->nlink = buf->st_nlink;
27 p->uid = buf->st_uid;
28 p->gid = buf->st_gid;
29 p->size = buf->st_size;
30 p->atime.tv_sec = buf->st_atime;
31 p->atime.tv_nsec = 0;
32 p->ctime.tv_sec = buf->st_ctime;
33 p->ctime.tv_nsec = 0;
34 p->mtime.tv_sec = buf->st_mtime;
35 p->mtime.tv_nsec = 0;
36 p->blksize = buf->st_blksize;
37 p->blocks = buf->st_blocks;
38 p->maj = os_major(buf->st_rdev);
39 p->min = os_minor(buf->st_rdev);
40}
41
42int stat_file(const char *path, struct hostfs_stat *p, int fd)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043{
44 struct stat64 buf;
45
Jeff Dike84b3db02007-10-16 01:27:13 -070046 if (fd >= 0) {
Alberto Bertogli5822b7f2007-05-08 00:23:16 -070047 if (fstat64(fd, &buf) < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -070048 return -errno;
Jeff Dike84b3db02007-10-16 01:27:13 -070049 } else if (lstat64(path, &buf) < 0) {
Jeff Dikef1adc052007-05-08 00:23:18 -070050 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -070051 }
Al Viro39b743c2010-06-06 20:08:56 -040052 stat64_to_hostfs(&buf, p);
Jeff Dikef1adc052007-05-08 00:23:18 -070053 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054}
55
56int file_type(const char *path, int *maj, int *min)
57{
58 struct stat64 buf;
59
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (lstat64(path, &buf) < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -070061 return -errno;
Jeff Dike84b3db02007-10-16 01:27:13 -070062 /*
63 * We cannot pass rdev as is because glibc and the kernel disagree
64 * about its definition.
65 */
66 if (maj != NULL)
Al Viro005a59e2009-04-21 01:27:08 -040067 *maj = os_major(buf.st_rdev);
Jeff Dike84b3db02007-10-16 01:27:13 -070068 if (min != NULL)
Al Viro005a59e2009-04-21 01:27:08 -040069 *min = os_minor(buf.st_rdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Jeff Dike84b3db02007-10-16 01:27:13 -070071 if (S_ISDIR(buf.st_mode))
72 return OS_TYPE_DIR;
73 else if (S_ISLNK(buf.st_mode))
74 return OS_TYPE_SYMLINK;
75 else if (S_ISCHR(buf.st_mode))
76 return OS_TYPE_CHARDEV;
77 else if (S_ISBLK(buf.st_mode))
78 return OS_TYPE_BLOCKDEV;
79 else if (S_ISFIFO(buf.st_mode))
80 return OS_TYPE_FIFO;
81 else if (S_ISSOCK(buf.st_mode))
82 return OS_TYPE_SOCK;
Jeff Dikef1adc052007-05-08 00:23:18 -070083 else return OS_TYPE_FILE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084}
85
86int access_file(char *path, int r, int w, int x)
87{
88 int mode = 0;
89
Jeff Dike84b3db02007-10-16 01:27:13 -070090 if (r)
91 mode = R_OK;
92 if (w)
93 mode |= W_OK;
94 if (x)
95 mode |= X_OK;
96 if (access(path, mode) != 0)
Jeff Dikef1adc052007-05-08 00:23:18 -070097 return -errno;
98 else return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099}
100
101int open_file(char *path, int r, int w, int append)
102{
103 int mode = 0, fd;
104
Jeff Dike84b3db02007-10-16 01:27:13 -0700105 if (r && !w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 mode = O_RDONLY;
Jeff Dike84b3db02007-10-16 01:27:13 -0700107 else if (!r && w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 mode = O_WRONLY;
Jeff Dike84b3db02007-10-16 01:27:13 -0700109 else if (r && w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 mode = O_RDWR;
111 else panic("Impossible mode in open_file");
112
Jeff Dike84b3db02007-10-16 01:27:13 -0700113 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 mode |= O_APPEND;
115 fd = open64(path, mode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700116 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700117 return -errno;
118 else return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119}
120
121void *open_dir(char *path, int *err_out)
122{
123 DIR *dir;
124
125 dir = opendir(path);
126 *err_out = errno;
Jeff Dike84b3db02007-10-16 01:27:13 -0700127 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700128 return NULL;
129 return dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
132char *read_dir(void *stream, unsigned long long *pos,
133 unsigned long long *ino_out, int *len_out)
134{
135 DIR *dir = stream;
136 struct dirent *ent;
137
138 seekdir(dir, *pos);
139 ent = readdir(dir);
Jeff Dike84b3db02007-10-16 01:27:13 -0700140 if (ent == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700141 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 *len_out = strlen(ent->d_name);
143 *ino_out = ent->d_ino;
144 *pos = telldir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700145 return ent->d_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
148int read_file(int fd, unsigned long long *offset, char *buf, int len)
149{
150 int n;
151
152 n = pread64(fd, buf, len, *offset);
Jeff Dike84b3db02007-10-16 01:27:13 -0700153 if (n < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700154 return -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 *offset += n;
Jeff Dikef1adc052007-05-08 00:23:18 -0700156 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157}
158
159int write_file(int fd, unsigned long long *offset, const char *buf, int len)
160{
161 int n;
162
163 n = pwrite64(fd, buf, len, *offset);
Jeff Dike84b3db02007-10-16 01:27:13 -0700164 if (n < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700165 return -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 *offset += n;
Jeff Dikef1adc052007-05-08 00:23:18 -0700167 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
170int lseek_file(int fd, long long offset, int whence)
171{
172 int ret;
173
174 ret = lseek64(fd, offset, whence);
Jeff Dike84b3db02007-10-16 01:27:13 -0700175 if (ret < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700176 return -errno;
177 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178}
179
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700180int fsync_file(int fd, int datasync)
181{
182 int ret;
183 if (datasync)
184 ret = fdatasync(fd);
185 else
186 ret = fsync(fd);
187
188 if (ret < 0)
189 return -errno;
190 return 0;
191}
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193void close_file(void *stream)
194{
195 close(*((int *) stream));
196}
197
198void close_dir(void *stream)
199{
200 closedir(stream);
201}
202
203int file_create(char *name, int ur, int uw, int ux, int gr,
204 int gw, int gx, int or, int ow, int ox)
205{
206 int mode, fd;
207
208 mode = 0;
209 mode |= ur ? S_IRUSR : 0;
210 mode |= uw ? S_IWUSR : 0;
211 mode |= ux ? S_IXUSR : 0;
212 mode |= gr ? S_IRGRP : 0;
213 mode |= gw ? S_IWGRP : 0;
214 mode |= gx ? S_IXGRP : 0;
215 mode |= or ? S_IROTH : 0;
216 mode |= ow ? S_IWOTH : 0;
217 mode |= ox ? S_IXOTH : 0;
218 fd = open64(name, O_CREAT | O_RDWR, mode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700219 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700220 return -errno;
221 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
223
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700224int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
Al Viro39b743c2010-06-06 20:08:56 -0400226 struct hostfs_stat st;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700227 struct timeval times[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 int err, ma;
229
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700230 if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
231 if (fd >= 0) {
232 if (fchmod(fd, attrs->ia_mode) != 0)
233 return (-errno);
234 } else if (chmod(file, attrs->ia_mode) != 0) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700235 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700238 if (attrs->ia_valid & HOSTFS_ATTR_UID) {
239 if (fd >= 0) {
240 if (fchown(fd, attrs->ia_uid, -1))
Jeff Dikef1adc052007-05-08 00:23:18 -0700241 return -errno;
Jeff Dike84b3db02007-10-16 01:27:13 -0700242 } else if (chown(file, attrs->ia_uid, -1)) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700243 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 }
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700246 if (attrs->ia_valid & HOSTFS_ATTR_GID) {
247 if (fd >= 0) {
248 if (fchown(fd, -1, attrs->ia_gid))
Jeff Dikef1adc052007-05-08 00:23:18 -0700249 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700250 } else if (chown(file, -1, attrs->ia_gid)) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700251 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 }
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700254 if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
255 if (fd >= 0) {
256 if (ftruncate(fd, attrs->ia_size))
Jeff Dikef1adc052007-05-08 00:23:18 -0700257 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700258 } else if (truncate(file, attrs->ia_size)) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700259 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Jeff Dike84b3db02007-10-16 01:27:13 -0700263 /*
264 * Update accessed and/or modified time, in two parts: first set
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700265 * times according to the changes to perform, and then call futimes()
Jeff Dike84b3db02007-10-16 01:27:13 -0700266 * or utimes() to apply them.
267 */
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700268 ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
269 if (attrs->ia_valid & ma) {
Al Viro39b743c2010-06-06 20:08:56 -0400270 err = stat_file(file, &st, fd);
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700271 if (err != 0)
272 return err;
273
Al Viro39b743c2010-06-06 20:08:56 -0400274 times[0].tv_sec = st.atime.tv_sec;
275 times[0].tv_usec = st.atime.tv_nsec / 1000;
276 times[1].tv_sec = st.mtime.tv_sec;
277 times[1].tv_usec = st.mtime.tv_nsec / 1000;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700278
279 if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
280 times[0].tv_sec = attrs->ia_atime.tv_sec;
Dominique Quatravauxd7b88512008-02-04 22:31:15 -0800281 times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700283 if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
284 times[1].tv_sec = attrs->ia_mtime.tv_sec;
Dominique Quatravauxd7b88512008-02-04 22:31:15 -0800285 times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700286 }
287
288 if (fd >= 0) {
289 if (futimes(fd, times) != 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return -errno;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700291 } else if (utimes(file, times) != 0) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700292 return -errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
294 }
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700295
Jeff Dikebaabd152007-10-16 01:27:13 -0700296 /* Note: ctime is not handled */
Jeff Dike84b3db02007-10-16 01:27:13 -0700297 if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) {
Al Viro39b743c2010-06-06 20:08:56 -0400298 err = stat_file(file, &st, fd);
299 attrs->ia_atime = st.atime;
300 attrs->ia_mtime = st.mtime;
Jeff Dike84b3db02007-10-16 01:27:13 -0700301 if (err != 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700302 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700304 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
307int make_symlink(const char *from, const char *to)
308{
309 int err;
310
311 err = symlink(to, from);
Jeff Dike84b3db02007-10-16 01:27:13 -0700312 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700313 return -errno;
314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316
317int unlink_file(const char *file)
318{
319 int err;
320
321 err = unlink(file);
Jeff Dike84b3db02007-10-16 01:27:13 -0700322 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700323 return -errno;
324 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325}
326
327int do_mkdir(const char *file, int mode)
328{
329 int err;
330
331 err = mkdir(file, mode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700332 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700333 return -errno;
334 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335}
336
337int do_rmdir(const char *file)
338{
339 int err;
340
341 err = rmdir(file);
Jeff Dike84b3db02007-10-16 01:27:13 -0700342 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700343 return -errno;
344 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345}
346
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800347int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 int err;
350
Al Viro005a59e2009-04-21 01:27:08 -0400351 err = mknod(file, mode, os_makedev(major, minor));
Jeff Dike84b3db02007-10-16 01:27:13 -0700352 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700353 return -errno;
354 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
357int link_file(const char *to, const char *from)
358{
359 int err;
360
361 err = link(to, from);
Jeff Dike84b3db02007-10-16 01:27:13 -0700362 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700363 return -errno;
364 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
WANG Congea7e7432008-11-19 15:36:46 -0800367int hostfs_do_readlink(char *file, char *buf, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 int n;
370
371 n = readlink(file, buf, size);
Jeff Dike84b3db02007-10-16 01:27:13 -0700372 if (n < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700373 return -errno;
Jeff Dike84b3db02007-10-16 01:27:13 -0700374 if (n < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 buf[n] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700376 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
379int rename_file(char *from, char *to)
380{
381 int err;
382
383 err = rename(from, to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700384 if (err < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700385 return -errno;
386 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
389int do_statfs(char *root, long *bsize_out, long long *blocks_out,
390 long long *bfree_out, long long *bavail_out,
391 long long *files_out, long long *ffree_out,
392 void *fsid_out, int fsid_size, long *namelen_out,
393 long *spare_out)
394{
395 struct statfs64 buf;
396 int err;
397
398 err = statfs64(root, &buf);
Jeff Dike84b3db02007-10-16 01:27:13 -0700399 if (err < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700400 return -errno;
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 *bsize_out = buf.f_bsize;
403 *blocks_out = buf.f_blocks;
404 *bfree_out = buf.f_bfree;
405 *bavail_out = buf.f_bavail;
406 *files_out = buf.f_files;
407 *ffree_out = buf.f_ffree;
408 memcpy(fsid_out, &buf.f_fsid,
409 sizeof(buf.f_fsid) > fsid_size ? fsid_size :
410 sizeof(buf.f_fsid));
411 *namelen_out = buf.f_namelen;
412 spare_out[0] = buf.f_spare[0];
413 spare_out[1] = buf.f_spare[1];
414 spare_out[2] = buf.f_spare[2];
415 spare_out[3] = buf.f_spare[3];
416 spare_out[4] = buf.f_spare[4];
Jeff Dikef1adc052007-05-08 00:23:18 -0700417 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}