This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / hostfs / host_file.c
1 /* 
2  * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/stddef.h"
7 #include "linux/string.h"
8 #include "linux/errno.h"
9 #include "linux/types.h"
10 #include "linux/slab.h"
11 #include "linux/fs.h"
12 #include "asm/fcntl.h"
13 #include "hostfs.h"
14 #include "filehandle.h"
15
16 extern int append;
17
18 char *get_path(const char *path[], char *buf, int size)
19 {
20         const char **s;
21         char *p;
22         int new = 1;
23
24         for(s = path; *s != NULL; s++){
25                 new += strlen(*s);
26                 if((*(s + 1) != NULL) && (strlen(*s) > 0) && 
27                    ((*s)[strlen(*s) - 1] != '/'))
28                         new++;
29         }
30
31         if(new > size){
32                 buf = kmalloc(new, GFP_KERNEL);
33                 if(buf == NULL)
34                         return(NULL);
35         }
36
37         p = buf;
38         for(s = path; *s != NULL; s++){
39                 strcpy(p, *s);
40                 p += strlen(*s);
41                 if((*(s + 1) != NULL) && (strlen(*s) > 0) && 
42                    ((*s)[strlen(*s) - 1] != '/'))
43                         strcpy(p++, "/");
44         }
45                 
46         return(buf);
47 }
48
49 void free_path(const char *buf, char *tmp)
50 {
51         if((buf != tmp) && (buf != NULL))
52                 kfree((char *) buf);
53 }
54
55 int host_open_file(const char *path[], int r, int w, struct file_handle *fh)
56 {
57         char tmp[HOSTFS_BUFSIZE], *file;
58         int mode = 0, err;
59         struct openflags flags = OPENFLAGS();
60
61         if (r)
62                 flags = of_read(flags);
63         if (w)
64                 flags = of_write(flags);
65         if(append)
66                 flags = of_append(flags);
67
68         err = -ENOMEM;
69         file = get_path(path, tmp, sizeof(tmp));
70         if(file == NULL)
71                 goto out;
72         
73         err = open_filehandle(file, flags, mode, fh);
74  out:
75         free_path(file, tmp);
76         return(err);
77 }
78
79 void *host_open_dir(const char *path[])
80 {
81         char tmp[HOSTFS_BUFSIZE], *file;
82         void *dir = ERR_PTR(-ENOMEM);
83
84         file = get_path(path, tmp, sizeof(tmp));
85         if(file == NULL)
86                 goto out;
87         
88         dir = open_dir(file);
89  out:
90         free_path(file, tmp);
91         return(dir);
92 }
93
94 char *host_read_dir(void *stream, unsigned long long *pos, 
95                     unsigned long long *ino_out, int *len_out)
96 {
97         int err;
98         char *name;
99
100         err = os_seek_dir(stream, *pos);
101         if(err)
102                 return(ERR_PTR(err));
103
104         err = os_read_dir(stream, ino_out, &name);
105         if(err)
106                 return(ERR_PTR(err));
107
108         if(name == NULL)
109                 return(NULL);
110
111         *len_out = strlen(name);
112         *pos = os_tell_dir(stream);
113         return(name);
114 }
115
116 int host_file_type(const char *path[], int *rdev)
117 {
118         char tmp[HOSTFS_BUFSIZE], *file;
119         struct uml_stat buf;
120         int ret;
121
122         ret = -ENOMEM;
123         file = get_path(path, tmp, sizeof(tmp));
124         if(file == NULL)
125                 goto out;
126
127         if(rdev != NULL){
128                 ret = os_lstat_file(file, &buf);
129                 if(ret)
130                         goto out;
131                 *rdev = MKDEV(buf.ust_rmajor, buf.ust_rminor);
132         }
133
134         ret = os_file_type(file);
135  out:
136         free_path(file, tmp);
137         return(ret);
138 }
139
140 int host_create_file(const char *path[], int mode, struct file_handle *fh)
141 {
142         char tmp[HOSTFS_BUFSIZE], *file;
143         int err = -ENOMEM;
144
145         file = get_path(path, tmp, sizeof(tmp));
146         if(file == NULL)
147                 goto out;
148
149         err = open_filehandle(file, of_create(of_rdwr(OPENFLAGS())), mode, fh);
150  out:
151         free_path(file, tmp);
152         return(err);
153 }
154
155 static int do_stat_file(const char *path, int *dev_out, 
156                         unsigned long long *inode_out, int *mode_out, 
157                         int *nlink_out, int *uid_out, int *gid_out, 
158                         unsigned long long *size_out, unsigned long *atime_out,
159                         unsigned long *mtime_out, unsigned long *ctime_out,
160                         int *blksize_out, unsigned long long *blocks_out)
161 {
162         struct uml_stat buf;
163         int err;
164
165         err = os_lstat_file(path, &buf);
166         if(err < 0)
167                 return(err);
168
169         if(dev_out != NULL) *dev_out = MKDEV(buf.ust_major, buf.ust_minor);
170         if(inode_out != NULL) *inode_out = buf.ust_ino;
171         if(mode_out != NULL) *mode_out = buf.ust_mode;
172         if(nlink_out != NULL) *nlink_out = buf.ust_nlink;
173         if(uid_out != NULL) *uid_out = buf.ust_uid;
174         if(gid_out != NULL) *gid_out = buf.ust_gid;
175         if(size_out != NULL) *size_out = buf.ust_size;
176         if(atime_out != NULL) *atime_out = buf.ust_atime;
177         if(mtime_out != NULL) *mtime_out = buf.ust_mtime;
178         if(ctime_out != NULL) *ctime_out = buf.ust_ctime;
179         if(blksize_out != NULL) *blksize_out = buf.ust_blksize;
180         if(blocks_out != NULL) *blocks_out = buf.ust_blocks;
181
182         return(0);
183 }
184
185 int host_stat_file(const char *path[], int *dev_out,
186                    unsigned long long *inode_out, int *mode_out, 
187                    int *nlink_out, int *uid_out, int *gid_out, 
188                    unsigned long long *size_out, unsigned long *atime_out,
189                    unsigned long *mtime_out, unsigned long *ctime_out,
190                    int *blksize_out, unsigned long long *blocks_out)
191 {
192         char tmp[HOSTFS_BUFSIZE], *file;
193         int err;
194
195         err = -ENOMEM;
196         file = get_path(path, tmp, sizeof(tmp));
197         if(file == NULL)
198                 goto out;
199
200         err = do_stat_file(file, dev_out, inode_out, mode_out, nlink_out, 
201                            uid_out, gid_out, size_out, atime_out, mtime_out,
202                            ctime_out, blksize_out, blocks_out);
203  out:
204         free_path(file, tmp);
205         return(err);
206 }
207
208 int host_set_attr(const char *path[], struct externfs_iattr *attrs)
209 {
210         char tmp[HOSTFS_BUFSIZE], *file;
211         unsigned long time;
212         int err = 0, ma;
213
214         if(append && (attrs->ia_valid & EXTERNFS_ATTR_SIZE))
215                 return(-EPERM);
216
217         err = -ENOMEM;
218         file = get_path(path, tmp, sizeof(tmp));
219         if(file == NULL)
220                 goto out;
221
222         if(attrs->ia_valid & EXTERNFS_ATTR_MODE){
223                 err = os_set_file_perms(file, attrs->ia_mode);
224                 if(err < 0)
225                         goto out;
226         }
227         if(attrs->ia_valid & EXTERNFS_ATTR_UID){
228                 err = os_set_file_owner(file, attrs->ia_uid, -1);
229                 if(err < 0)
230                         goto out;
231         }
232         if(attrs->ia_valid & EXTERNFS_ATTR_GID){
233                 err = os_set_file_owner(file, -1, attrs->ia_gid);
234                 if(err < 0)
235                         goto out;
236         }
237         if(attrs->ia_valid & EXTERNFS_ATTR_SIZE){
238                 err = os_truncate_file(file, attrs->ia_size);
239                 if(err < 0)
240                         goto out;
241         }
242         ma = EXTERNFS_ATTR_ATIME_SET | EXTERNFS_ATTR_MTIME_SET;
243         if((attrs->ia_valid & ma) == ma){
244                 err = os_set_file_time(file, attrs->ia_atime, attrs->ia_mtime);
245                 if(err)
246                         goto out;
247         }
248         else {
249                 if(attrs->ia_valid & EXTERNFS_ATTR_ATIME_SET){
250                         err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
251                                            NULL, NULL, NULL, &time, 
252                                            NULL, NULL, NULL);
253                         if(err != 0)
254                                 goto out;
255
256                         err = os_set_file_time(file, attrs->ia_atime, time);
257                         if(err)
258                                 goto out;
259                 }
260                 if(attrs->ia_valid & EXTERNFS_ATTR_MTIME_SET){
261                         err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
262                                            NULL, NULL, &time, NULL, 
263                                            NULL, NULL, NULL);
264                         if(err != 0)
265                                 goto out;
266
267                         err = os_set_file_time(file, time, attrs->ia_mtime);
268                         if(err)
269                                 goto out;
270                 }
271         }
272         if(attrs->ia_valid & EXTERNFS_ATTR_CTIME) ;
273         if(attrs->ia_valid & (EXTERNFS_ATTR_ATIME | EXTERNFS_ATTR_MTIME)){
274                 err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
275                                    NULL, NULL, &attrs->ia_atime, 
276                                    &attrs->ia_mtime, NULL, NULL, NULL);
277                 if(err != 0)
278                         goto out;
279         }
280
281         err = 0;
282  out:
283         free_path(file, tmp);
284         return(err);
285 }
286
287 int host_make_symlink(const char *from[], const char *to)
288 {
289         char tmp[HOSTFS_BUFSIZE], *file;
290         int err = -ENOMEM;
291
292         file = get_path(from, tmp, sizeof(tmp));
293         if(file == NULL)
294                 goto out;
295         
296         err = os_make_symlink(to, file);
297  out:
298         free_path(file, tmp);
299         return(err);
300 }
301
302 int host_unlink_file(const char *path[])
303 {
304         char tmp[HOSTFS_BUFSIZE], *file;
305         int err = -ENOMEM;
306
307         if(append)
308                 return(-EPERM);
309
310         file = get_path(path, tmp, sizeof(tmp));
311         if(file == NULL)
312                 goto out;
313
314         err = os_remove_file(file);
315  out:
316         free_path(file, tmp);
317         return(err);
318 }
319
320 int host_make_dir(const char *path[], int mode)
321 {
322         char tmp[HOSTFS_BUFSIZE], *file;
323         int err = -ENOMEM;
324
325         file = get_path(path, tmp, sizeof(tmp));
326         if(file == NULL)
327                 goto out;
328
329         err = os_make_dir(file, mode);
330  out:
331         free_path(file, tmp);
332         return(err);
333 }
334
335 int host_remove_dir(const char *path[])
336 {
337         char tmp[HOSTFS_BUFSIZE], *file;
338         int err = -ENOMEM;
339
340         file = get_path(path, tmp, sizeof(tmp));
341         if(file == NULL)
342                 goto out;
343
344         err = os_remove_dir(file);
345  out:
346         free_path(file, tmp);
347         return(err);
348 }
349
350 int host_link_file(const char *to[], const char *from[])
351 {
352         char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t;
353         int err = -ENOMEM;
354
355         f = get_path(from, from_tmp, sizeof(from_tmp));
356         t = get_path(to, to_tmp, sizeof(to_tmp));
357         if((f == NULL) || (t == NULL))
358                 goto out;
359
360         err = os_link_file(t, f);
361  out:
362         free_path(f, from_tmp);
363         free_path(t, to_tmp);
364         return(err);
365 }
366
367 int host_read_link(const char *path[], char *buf, int size)
368 {
369         char tmp[HOSTFS_BUFSIZE], *file;
370         int n = -ENOMEM;
371
372         file = get_path(path, tmp, sizeof(tmp));
373         if(file == NULL)
374                 goto out;
375
376         n = os_read_symlink(file, buf, size);
377         if(n < size) 
378                 buf[n] = '\0';
379  out:
380         free_path(file, tmp);
381         return(n);
382 }
383
384 int host_rename_file(const char *from[], const char *to[])
385 {
386         char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t;
387         int err = -ENOMEM;
388
389         f = get_path(from, from_tmp, sizeof(from_tmp));
390         t = get_path(to, to_tmp, sizeof(to_tmp));
391         if((f == NULL) || (t == NULL))
392                 goto out;
393
394         err = os_move_file(f, t);
395  out:
396         free_path(f, from_tmp);
397         free_path(t, to_tmp);
398         return(err);
399 }
400
401 int host_stat_fs(const char *path[], long *bsize_out, long long *blocks_out, 
402                  long long *bfree_out, long long *bavail_out, 
403                  long long *files_out, long long *ffree_out, void *fsid_out, 
404                  int fsid_size, long *namelen_out, long *spare_out)
405 {
406         char tmp[HOSTFS_BUFSIZE], *file;
407         int err = -ENOMEM;
408
409         file = get_path(path, tmp, sizeof(tmp));
410         if(file == NULL)
411                 goto out;
412
413         err = os_stat_filesystem(file, bsize_out, blocks_out, bfree_out, 
414                                  bavail_out, files_out, ffree_out, fsid_out, 
415                                  fsid_size, namelen_out, spare_out);
416  out:
417         free_path(file, tmp);
418         return(err);
419 }
420
421 char *generic_host_read_dir(void *stream, unsigned long long *pos, 
422                             unsigned long long *ino_out, int *len_out, 
423                             void *mount)
424 {
425         return(host_read_dir(stream, pos, ino_out, len_out));
426 }
427
428 int generic_host_truncate_file(struct file_handle *fh, __u64 size, void *m)
429 {
430         return(truncate_file(fh, size));
431 }
432
433 /*
434  * Overrides for Emacs so that we follow Linus's tabbing style.
435  * Emacs will notice this stuff at the end of the file and automatically
436  * adjust the settings for this buffer only.  This must remain at the end
437  * of the file.
438  * ---------------------------------------------------------------------------
439  * Local variables:
440  * c-file-style: "linux"
441  * End:
442  */