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