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