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