aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hostfs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/hostfs
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'fs/hostfs')
-rw-r--r--fs/hostfs/Makefile11
-rw-r--r--fs/hostfs/hostfs.h100
-rw-r--r--fs/hostfs/hostfs_kern.c1045
-rw-r--r--fs/hostfs/hostfs_user.c362
4 files changed, 1518 insertions, 0 deletions
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
new file mode 100644
index 00000000000..d5beaffad43
--- /dev/null
+++ b/fs/hostfs/Makefile
@@ -0,0 +1,11 @@
1#
2# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6hostfs-objs := hostfs_kern.o hostfs_user.o
7
8obj-y :=
9obj-$(CONFIG_HOSTFS) += hostfs.o
10
11include arch/um/scripts/Makefile.rules
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
new file mode 100644
index 00000000000..c1516d013bf
--- /dev/null
+++ b/fs/hostfs/hostfs.h
@@ -0,0 +1,100 @@
1#ifndef __UM_FS_HOSTFS
2#define __UM_FS_HOSTFS
3
4#include "os.h"
5
6/* These are exactly the same definitions as in fs.h, but the names are
7 * changed so that this file can be included in both kernel and user files.
8 */
9
10#define HOSTFS_ATTR_MODE 1
11#define HOSTFS_ATTR_UID 2
12#define HOSTFS_ATTR_GID 4
13#define HOSTFS_ATTR_SIZE 8
14#define HOSTFS_ATTR_ATIME 16
15#define HOSTFS_ATTR_MTIME 32
16#define HOSTFS_ATTR_CTIME 64
17#define HOSTFS_ATTR_ATIME_SET 128
18#define HOSTFS_ATTR_MTIME_SET 256
19
20/* These two are unused by hostfs. */
21#define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */
22#define HOSTFS_ATTR_ATTR_FLAG 1024
23
24/* If you are very careful, you'll notice that these two are missing:
25 *
26 * #define ATTR_KILL_SUID 2048
27 * #define ATTR_KILL_SGID 4096
28 *
29 * and this is because they were added in 2.5 development in this patch:
30 *
31 * http://linux.bkbits.net:8080/linux-2.5/
32 * cset@3caf4a12k4XgDzK7wyK-TGpSZ9u2Ww?nav=index.html
33 * |src/.|src/include|src/include/linux|related/include/linux/fs.h
34 *
35 * Actually, they are not needed by most ->setattr() methods - they are set by
36 * callers of notify_change() to notify that the setuid/setgid bits must be
37 * dropped.
38 * notify_change() will delete those flags, make sure attr->ia_valid & ATTR_MODE
39 * is on, and remove the appropriate bits from attr->ia_mode (attr is a
40 * "struct iattr *"). -BlaisorBlade
41 */
42
43struct hostfs_iattr {
44 unsigned int ia_valid;
45 mode_t ia_mode;
46 uid_t ia_uid;
47 gid_t ia_gid;
48 loff_t ia_size;
49 struct timespec ia_atime;
50 struct timespec ia_mtime;
51 struct timespec ia_ctime;
52 unsigned int ia_attr_flags;
53};
54
55extern int stat_file(const char *path, unsigned long long *inode_out,
56 int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
57 unsigned long long *size_out, struct timespec *atime_out,
58 struct timespec *mtime_out, struct timespec *ctime_out,
59 int *blksize_out, unsigned long long *blocks_out);
60extern int access_file(char *path, int r, int w, int x);
61extern int open_file(char *path, int r, int w, int append);
62extern int file_type(const char *path, int *maj, int *min);
63extern void *open_dir(char *path, int *err_out);
64extern char *read_dir(void *stream, unsigned long long *pos,
65 unsigned long long *ino_out, int *len_out);
66extern void close_file(void *stream);
67extern void close_dir(void *stream);
68extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
69extern int write_file(int fd, unsigned long long *offset, const char *buf,
70 int len);
71extern int lseek_file(int fd, long long offset, int whence);
72extern int file_create(char *name, int ur, int uw, int ux, int gr,
73 int gw, int gx, int or, int ow, int ox);
74extern int set_attr(const char *file, struct hostfs_iattr *attrs);
75extern int make_symlink(const char *from, const char *to);
76extern int unlink_file(const char *file);
77extern int do_mkdir(const char *file, int mode);
78extern int do_rmdir(const char *file);
79extern int do_mknod(const char *file, int mode, int dev);
80extern int link_file(const char *from, const char *to);
81extern int do_readlink(char *file, char *buf, int size);
82extern int rename_file(char *from, char *to);
83extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
84 long long *bfree_out, long long *bavail_out,
85 long long *files_out, long long *ffree_out,
86 void *fsid_out, int fsid_size, long *namelen_out,
87 long *spare_out);
88
89#endif
90
91/*
92 * Overrides for Emacs so that we follow Linus's tabbing style.
93 * Emacs will notice this stuff at the end of the file and automatically
94 * adjust the settings for this buffer only. This must remain at the end
95 * of the file.
96 * ---------------------------------------------------------------------------
97 * Local variables:
98 * c-file-style: "linux"
99 * End:
100 */
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
new file mode 100644
index 00000000000..a88ad292485
--- /dev/null
+++ b/fs/hostfs/hostfs_kern.c
@@ -0,0 +1,1045 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 *
5 * Ported the filesystem routines to 2.5.
6 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
7 */
8
9#include <linux/stddef.h>
10#include <linux/fs.h>
11#include <linux/version.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/slab.h>
15#include <linux/pagemap.h>
16#include <linux/blkdev.h>
17#include <linux/list.h>
18#include <linux/root_dev.h>
19#include <linux/statfs.h>
20#include <linux/kdev_t.h>
21#include <asm/uaccess.h>
22#include "hostfs.h"
23#include "kern_util.h"
24#include "kern.h"
25#include "user_util.h"
26#include "2_5compat.h"
27#include "init.h"
28
29struct hostfs_inode_info {
30 char *host_filename;
31 int fd;
32 int mode;
33 struct inode vfs_inode;
34};
35
36static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
37{
38 return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
39}
40
41#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode)
42
43int hostfs_d_delete(struct dentry *dentry)
44{
45 return(1);
46}
47
48struct dentry_operations hostfs_dentry_ops = {
49 .d_delete = hostfs_d_delete,
50};
51
52/* Changed in hostfs_args before the kernel starts running */
53static char *root_ino = "/";
54static int append = 0;
55
56#define HOSTFS_SUPER_MAGIC 0x00c0ffee
57
58static struct inode_operations hostfs_iops;
59static struct inode_operations hostfs_dir_iops;
60static struct address_space_operations hostfs_link_aops;
61
62#ifndef MODULE
63static int __init hostfs_args(char *options, int *add)
64{
65 char *ptr;
66
67 ptr = strchr(options, ',');
68 if(ptr != NULL)
69 *ptr++ = '\0';
70 if(*options != '\0')
71 root_ino = options;
72
73 options = ptr;
74 while(options){
75 ptr = strchr(options, ',');
76 if(ptr != NULL)
77 *ptr++ = '\0';
78 if(*options != '\0'){
79 if(!strcmp(options, "append"))
80 append = 1;
81 else printf("hostfs_args - unsupported option - %s\n",
82 options);
83 }
84 options = ptr;
85 }
86 return(0);
87}
88
89__uml_setup("hostfs=", hostfs_args,
90"hostfs=<root dir>,<flags>,...\n"
91" This is used to set hostfs parameters. The root directory argument\n"
92" is used to confine all hostfs mounts to within the specified directory\n"
93" tree on the host. If this isn't specified, then a user inside UML can\n"
94" mount anything on the host that's accessible to the user that's running\n"
95" it.\n"
96" The only flag currently supported is 'append', which specifies that all\n"
97" files opened by hostfs will be opened in append mode.\n\n"
98);
99#endif
100
101static char *dentry_name(struct dentry *dentry, int extra)
102{
103 struct dentry *parent;
104 char *root, *name;
105 int len;
106
107 len = 0;
108 parent = dentry;
109 while(parent->d_parent != parent){
110 len += parent->d_name.len + 1;
111 parent = parent->d_parent;
112 }
113
114 root = HOSTFS_I(parent->d_inode)->host_filename;
115 len += strlen(root);
116 name = kmalloc(len + extra + 1, GFP_KERNEL);
117 if(name == NULL) return(NULL);
118
119 name[len] = '\0';
120 parent = dentry;
121 while(parent->d_parent != parent){
122 len -= parent->d_name.len + 1;
123 name[len] = '/';
124 strncpy(&name[len + 1], parent->d_name.name,
125 parent->d_name.len);
126 parent = parent->d_parent;
127 }
128 strncpy(name, root, strlen(root));
129 return(name);
130}
131
132static char *inode_name(struct inode *ino, int extra)
133{
134 struct dentry *dentry;
135
136 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
137 return(dentry_name(dentry, extra));
138}
139
140static int read_name(struct inode *ino, char *name)
141{
142 /* The non-int inode fields are copied into ints by stat_file and
143 * then copied into the inode because passing the actual pointers
144 * in and having them treated as int * breaks on big-endian machines
145 */
146 int err;
147 int i_mode, i_nlink, i_blksize;
148 unsigned long long i_size;
149 unsigned long long i_ino;
150 unsigned long long i_blocks;
151
152 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
153 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
154 &ino->i_ctime, &i_blksize, &i_blocks);
155 if(err)
156 return(err);
157
158 ino->i_ino = i_ino;
159 ino->i_mode = i_mode;
160 ino->i_nlink = i_nlink;
161 ino->i_size = i_size;
162 ino->i_blksize = i_blksize;
163 ino->i_blocks = i_blocks;
164 if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid()))
165 ino->i_uid = 0;
166 return(0);
167}
168
169static char *follow_link(char *link)
170{
171 int len, n;
172 char *name, *resolved, *end;
173
174 len = 64;
175 while(1){
176 n = -ENOMEM;
177 name = kmalloc(len, GFP_KERNEL);
178 if(name == NULL)
179 goto out;
180
181 n = do_readlink(link, name, len);
182 if(n < len)
183 break;
184 len *= 2;
185 kfree(name);
186 }
187 if(n < 0)
188 goto out_free;
189
190 if(*name == '/')
191 return(name);
192
193 end = strrchr(link, '/');
194 if(end == NULL)
195 return(name);
196
197 *(end + 1) = '\0';
198 len = strlen(link) + strlen(name) + 1;
199
200 resolved = kmalloc(len, GFP_KERNEL);
201 if(resolved == NULL){
202 n = -ENOMEM;
203 goto out_free;
204 }
205
206 sprintf(resolved, "%s%s", link, name);
207 kfree(name);
208 kfree(link);
209 return(resolved);
210
211 out_free:
212 kfree(name);
213 out:
214 return(ERR_PTR(n));
215}
216
217static int read_inode(struct inode *ino)
218{
219 char *name;
220 int err = 0;
221
222 /* Unfortunately, we are called from iget() when we don't have a dentry
223 * allocated yet.
224 */
225 if(list_empty(&ino->i_dentry))
226 goto out;
227
228 err = -ENOMEM;
229 name = inode_name(ino, 0);
230 if(name == NULL)
231 goto out;
232
233 if(file_type(name, NULL, NULL) == OS_TYPE_SYMLINK){
234 name = follow_link(name);
235 if(IS_ERR(name)){
236 err = PTR_ERR(name);
237 goto out;
238 }
239 }
240
241 err = read_name(ino, name);
242 kfree(name);
243 out:
244 return(err);
245}
246
247int hostfs_statfs(struct super_block *sb, struct kstatfs *sf)
248{
249 /* do_statfs uses struct statfs64 internally, but the linux kernel
250 * struct statfs still has 32-bit versions for most of these fields,
251 * so we convert them here
252 */
253 int err;
254 long long f_blocks;
255 long long f_bfree;
256 long long f_bavail;
257 long long f_files;
258 long long f_ffree;
259
260 err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename,
261 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
262 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
263 &sf->f_namelen, sf->f_spare);
264 if(err) return(err);
265 sf->f_blocks = f_blocks;
266 sf->f_bfree = f_bfree;
267 sf->f_bavail = f_bavail;
268 sf->f_files = f_files;
269 sf->f_ffree = f_ffree;
270 sf->f_type = HOSTFS_SUPER_MAGIC;
271 return(0);
272}
273
274static struct inode *hostfs_alloc_inode(struct super_block *sb)
275{
276 struct hostfs_inode_info *hi;
277
278 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
279 if(hi == NULL)
280 return(NULL);
281
282 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
283 .fd = -1,
284 .mode = 0 });
285 inode_init_once(&hi->vfs_inode);
286 return(&hi->vfs_inode);
287}
288
289static void hostfs_delete_inode(struct inode *inode)
290{
291 if(HOSTFS_I(inode)->fd != -1) {
292 close_file(&HOSTFS_I(inode)->fd);
293 HOSTFS_I(inode)->fd = -1;
294 }
295 clear_inode(inode);
296}
297
298static void hostfs_destroy_inode(struct inode *inode)
299{
300 if(HOSTFS_I(inode)->host_filename)
301 kfree(HOSTFS_I(inode)->host_filename);
302
303 /*XXX: This should not happen, probably. The check is here for
304 * additional safety.*/
305 if(HOSTFS_I(inode)->fd != -1) {
306 close_file(&HOSTFS_I(inode)->fd);
307 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
308 }
309
310 kfree(HOSTFS_I(inode));
311}
312
313static void hostfs_read_inode(struct inode *inode)
314{
315 read_inode(inode);
316}
317
318static struct super_operations hostfs_sbops = {
319 .alloc_inode = hostfs_alloc_inode,
320 .drop_inode = generic_delete_inode,
321 .delete_inode = hostfs_delete_inode,
322 .destroy_inode = hostfs_destroy_inode,
323 .read_inode = hostfs_read_inode,
324 .statfs = hostfs_statfs,
325};
326
327int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
328{
329 void *dir;
330 char *name;
331 unsigned long long next, ino;
332 int error, len;
333
334 name = dentry_name(file->f_dentry, 0);
335 if(name == NULL) return(-ENOMEM);
336 dir = open_dir(name, &error);
337 kfree(name);
338 if(dir == NULL) return(-error);
339 next = file->f_pos;
340 while((name = read_dir(dir, &next, &ino, &len)) != NULL){
341 error = (*filldir)(ent, name, len, file->f_pos,
342 ino, DT_UNKNOWN);
343 if(error) break;
344 file->f_pos = next;
345 }
346 close_dir(dir);
347 return(0);
348}
349
350int hostfs_file_open(struct inode *ino, struct file *file)
351{
352 char *name;
353 int mode = 0, r = 0, w = 0, fd;
354
355 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
356 if((mode & HOSTFS_I(ino)->mode) == mode)
357 return(0);
358
359 /* The file may already have been opened, but with the wrong access,
360 * so this resets things and reopens the file with the new access.
361 */
362 if(HOSTFS_I(ino)->fd != -1){
363 close_file(&HOSTFS_I(ino)->fd);
364 HOSTFS_I(ino)->fd = -1;
365 }
366
367 HOSTFS_I(ino)->mode |= mode;
368 if(HOSTFS_I(ino)->mode & FMODE_READ)
369 r = 1;
370 if(HOSTFS_I(ino)->mode & FMODE_WRITE)
371 w = 1;
372 if(w)
373 r = 1;
374
375 name = dentry_name(file->f_dentry, 0);
376 if(name == NULL)
377 return(-ENOMEM);
378
379 fd = open_file(name, r, w, append);
380 kfree(name);
381 if(fd < 0) return(fd);
382 FILE_HOSTFS_I(file)->fd = fd;
383
384 return(0);
385}
386
387int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
388{
389 return(0);
390}
391
392static struct file_operations hostfs_file_fops = {
393 .llseek = generic_file_llseek,
394 .read = generic_file_read,
395 .sendfile = generic_file_sendfile,
396 .aio_read = generic_file_aio_read,
397 .aio_write = generic_file_aio_write,
398 .readv = generic_file_readv,
399 .writev = generic_file_writev,
400 .write = generic_file_write,
401 .mmap = generic_file_mmap,
402 .open = hostfs_file_open,
403 .release = NULL,
404 .fsync = hostfs_fsync,
405};
406
407static struct file_operations hostfs_dir_fops = {
408 .llseek = generic_file_llseek,
409 .readdir = hostfs_readdir,
410 .read = generic_read_dir,
411};
412
413int hostfs_writepage(struct page *page, struct writeback_control *wbc)
414{
415 struct address_space *mapping = page->mapping;
416 struct inode *inode = mapping->host;
417 char *buffer;
418 unsigned long long base;
419 int count = PAGE_CACHE_SIZE;
420 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
421 int err;
422
423 if (page->index >= end_index)
424 count = inode->i_size & (PAGE_CACHE_SIZE-1);
425
426 buffer = kmap(page);
427 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
428
429 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
430 if(err != count){
431 ClearPageUptodate(page);
432 goto out;
433 }
434
435 if (base > inode->i_size)
436 inode->i_size = base;
437
438 if (PageError(page))
439 ClearPageError(page);
440 err = 0;
441
442 out:
443 kunmap(page);
444
445 unlock_page(page);
446 return err;
447}
448
449int hostfs_readpage(struct file *file, struct page *page)
450{
451 char *buffer;
452 long long start;
453 int err = 0;
454
455 start = (long long) page->index << PAGE_CACHE_SHIFT;
456 buffer = kmap(page);
457 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
458 PAGE_CACHE_SIZE);
459 if(err < 0) goto out;
460
461 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
462
463 flush_dcache_page(page);
464 SetPageUptodate(page);
465 if (PageError(page)) ClearPageError(page);
466 err = 0;
467 out:
468 kunmap(page);
469 unlock_page(page);
470 return(err);
471}
472
473int hostfs_prepare_write(struct file *file, struct page *page,
474 unsigned int from, unsigned int to)
475{
476 char *buffer;
477 long long start, tmp;
478 int err;
479
480 start = (long long) page->index << PAGE_CACHE_SHIFT;
481 buffer = kmap(page);
482 if(from != 0){
483 tmp = start;
484 err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer,
485 from);
486 if(err < 0) goto out;
487 }
488 if(to != PAGE_CACHE_SIZE){
489 start += to;
490 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to,
491 PAGE_CACHE_SIZE - to);
492 if(err < 0) goto out;
493 }
494 err = 0;
495 out:
496 kunmap(page);
497 return(err);
498}
499
500int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
501 unsigned to)
502{
503 struct address_space *mapping = page->mapping;
504 struct inode *inode = mapping->host;
505 char *buffer;
506 long long start;
507 int err = 0;
508
509 start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
510 buffer = kmap(page);
511 err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from,
512 to - from);
513 if(err > 0) err = 0;
514 if(!err && (start > inode->i_size))
515 inode->i_size = start;
516
517 kunmap(page);
518 return(err);
519}
520
521static struct address_space_operations hostfs_aops = {
522 .writepage = hostfs_writepage,
523 .readpage = hostfs_readpage,
524/* .set_page_dirty = __set_page_dirty_nobuffers, */
525 .prepare_write = hostfs_prepare_write,
526 .commit_write = hostfs_commit_write
527};
528
529static int init_inode(struct inode *inode, struct dentry *dentry)
530{
531 char *name;
532 int type, err = -ENOMEM;
533 int maj, min;
534 dev_t rdev = 0;
535
536 if(dentry){
537 name = dentry_name(dentry, 0);
538 if(name == NULL)
539 goto out;
540 type = file_type(name, &maj, &min);
541 /*Reencode maj and min with the kernel encoding.*/
542 rdev = MKDEV(maj, min);
543 kfree(name);
544 }
545 else type = OS_TYPE_DIR;
546
547 err = 0;
548 if(type == OS_TYPE_SYMLINK)
549 inode->i_op = &page_symlink_inode_operations;
550 else if(type == OS_TYPE_DIR)
551 inode->i_op = &hostfs_dir_iops;
552 else inode->i_op = &hostfs_iops;
553
554 if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
555 else inode->i_fop = &hostfs_file_fops;
556
557 if(type == OS_TYPE_SYMLINK)
558 inode->i_mapping->a_ops = &hostfs_link_aops;
559 else inode->i_mapping->a_ops = &hostfs_aops;
560
561 switch (type) {
562 case OS_TYPE_CHARDEV:
563 init_special_inode(inode, S_IFCHR, rdev);
564 break;
565 case OS_TYPE_BLOCKDEV:
566 init_special_inode(inode, S_IFBLK, rdev);
567 break;
568 case OS_TYPE_FIFO:
569 init_special_inode(inode, S_IFIFO, 0);
570 break;
571 case OS_TYPE_SOCK:
572 init_special_inode(inode, S_IFSOCK, 0);
573 break;
574 }
575 out:
576 return(err);
577}
578
579int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
580 struct nameidata *nd)
581{
582 struct inode *inode;
583 char *name;
584 int error, fd;
585
586 error = -ENOMEM;
587 inode = iget(dir->i_sb, 0);
588 if(inode == NULL) goto out;
589
590 error = init_inode(inode, dentry);
591 if(error)
592 goto out_put;
593
594 error = -ENOMEM;
595 name = dentry_name(dentry, 0);
596 if(name == NULL)
597 goto out_put;
598
599 fd = file_create(name,
600 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
601 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
602 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
603 if(fd < 0)
604 error = fd;
605 else error = read_name(inode, name);
606
607 kfree(name);
608 if(error)
609 goto out_put;
610
611 HOSTFS_I(inode)->fd = fd;
612 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
613 d_instantiate(dentry, inode);
614 return(0);
615
616 out_put:
617 iput(inode);
618 out:
619 return(error);
620}
621
622struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
623 struct nameidata *nd)
624{
625 struct inode *inode;
626 char *name;
627 int err;
628
629 err = -ENOMEM;
630 inode = iget(ino->i_sb, 0);
631 if(inode == NULL)
632 goto out;
633
634 err = init_inode(inode, dentry);
635 if(err)
636 goto out_put;
637
638 err = -ENOMEM;
639 name = dentry_name(dentry, 0);
640 if(name == NULL)
641 goto out_put;
642
643 err = read_name(inode, name);
644 kfree(name);
645 if(err == -ENOENT){
646 iput(inode);
647 inode = NULL;
648 }
649 else if(err)
650 goto out_put;
651
652 d_add(dentry, inode);
653 dentry->d_op = &hostfs_dentry_ops;
654 return(NULL);
655
656 out_put:
657 iput(inode);
658 out:
659 return(ERR_PTR(err));
660}
661
662static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
663{
664 char *file;
665 int len;
666
667 file = inode_name(ino, dentry->d_name.len + 1);
668 if(file == NULL) return(NULL);
669 strcat(file, "/");
670 len = strlen(file);
671 strncat(file, dentry->d_name.name, dentry->d_name.len);
672 file[len + dentry->d_name.len] = '\0';
673 return(file);
674}
675
676int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
677{
678 char *from_name, *to_name;
679 int err;
680
681 if((from_name = inode_dentry_name(ino, from)) == NULL)
682 return(-ENOMEM);
683 to_name = dentry_name(to, 0);
684 if(to_name == NULL){
685 kfree(from_name);
686 return(-ENOMEM);
687 }
688 err = link_file(to_name, from_name);
689 kfree(from_name);
690 kfree(to_name);
691 return(err);
692}
693
694int hostfs_unlink(struct inode *ino, struct dentry *dentry)
695{
696 char *file;
697 int err;
698
699 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
700 if(append)
701 return(-EPERM);
702
703 err = unlink_file(file);
704 kfree(file);
705 return(err);
706}
707
708int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
709{
710 char *file;
711 int err;
712
713 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
714 err = make_symlink(file, to);
715 kfree(file);
716 return(err);
717}
718
719int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
720{
721 char *file;
722 int err;
723
724 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
725 err = do_mkdir(file, mode);
726 kfree(file);
727 return(err);
728}
729
730int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
731{
732 char *file;
733 int err;
734
735 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
736 err = do_rmdir(file);
737 kfree(file);
738 return(err);
739}
740
741int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
742{
743 struct inode *inode;
744 char *name;
745 int err = -ENOMEM;
746
747 inode = iget(dir->i_sb, 0);
748 if(inode == NULL)
749 goto out;
750
751 err = init_inode(inode, dentry);
752 if(err)
753 goto out_put;
754
755 err = -ENOMEM;
756 name = dentry_name(dentry, 0);
757 if(name == NULL)
758 goto out_put;
759
760 init_special_inode(inode, mode, dev);
761 err = do_mknod(name, mode, dev);
762 if(err)
763 goto out_free;
764
765 err = read_name(inode, name);
766 kfree(name);
767 if(err)
768 goto out_put;
769
770 d_instantiate(dentry, inode);
771 return(0);
772
773 out_free:
774 kfree(name);
775 out_put:
776 iput(inode);
777 out:
778 return(err);
779}
780
781int hostfs_rename(struct inode *from_ino, struct dentry *from,
782 struct inode *to_ino, struct dentry *to)
783{
784 char *from_name, *to_name;
785 int err;
786
787 if((from_name = inode_dentry_name(from_ino, from)) == NULL)
788 return(-ENOMEM);
789 if((to_name = inode_dentry_name(to_ino, to)) == NULL){
790 kfree(from_name);
791 return(-ENOMEM);
792 }
793 err = rename_file(from_name, to_name);
794 kfree(from_name);
795 kfree(to_name);
796 return(err);
797}
798
799void hostfs_truncate(struct inode *ino)
800{
801 not_implemented();
802}
803
804int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
805{
806 char *name;
807 int r = 0, w = 0, x = 0, err;
808
809 if (desired & MAY_READ) r = 1;
810 if (desired & MAY_WRITE) w = 1;
811 if (desired & MAY_EXEC) x = 1;
812 name = inode_name(ino, 0);
813 if (name == NULL) return(-ENOMEM);
814
815 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
816 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
817 err = 0;
818 else
819 err = access_file(name, r, w, x);
820 kfree(name);
821 if(!err)
822 err = generic_permission(ino, desired, NULL);
823 return err;
824}
825
826int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
827{
828 struct hostfs_iattr attrs;
829 char *name;
830 int err;
831
832 err = inode_change_ok(dentry->d_inode, attr);
833 if (err)
834 return err;
835
836 if(append)
837 attr->ia_valid &= ~ATTR_SIZE;
838
839 attrs.ia_valid = 0;
840 if(attr->ia_valid & ATTR_MODE){
841 attrs.ia_valid |= HOSTFS_ATTR_MODE;
842 attrs.ia_mode = attr->ia_mode;
843 }
844 if(attr->ia_valid & ATTR_UID){
845 if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) &&
846 (attr->ia_uid == 0))
847 attr->ia_uid = getuid();
848 attrs.ia_valid |= HOSTFS_ATTR_UID;
849 attrs.ia_uid = attr->ia_uid;
850 }
851 if(attr->ia_valid & ATTR_GID){
852 if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) &&
853 (attr->ia_gid == 0))
854 attr->ia_gid = getgid();
855 attrs.ia_valid |= HOSTFS_ATTR_GID;
856 attrs.ia_gid = attr->ia_gid;
857 }
858 if(attr->ia_valid & ATTR_SIZE){
859 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
860 attrs.ia_size = attr->ia_size;
861 }
862 if(attr->ia_valid & ATTR_ATIME){
863 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
864 attrs.ia_atime = attr->ia_atime;
865 }
866 if(attr->ia_valid & ATTR_MTIME){
867 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
868 attrs.ia_mtime = attr->ia_mtime;
869 }
870 if(attr->ia_valid & ATTR_CTIME){
871 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
872 attrs.ia_ctime = attr->ia_ctime;
873 }
874 if(attr->ia_valid & ATTR_ATIME_SET){
875 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
876 }
877 if(attr->ia_valid & ATTR_MTIME_SET){
878 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
879 }
880 name = dentry_name(dentry, 0);
881 if(name == NULL) return(-ENOMEM);
882 err = set_attr(name, &attrs);
883 kfree(name);
884 if(err)
885 return(err);
886
887 return(inode_setattr(dentry->d_inode, attr));
888}
889
890int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
891 struct kstat *stat)
892{
893 generic_fillattr(dentry->d_inode, stat);
894 return(0);
895}
896
897static struct inode_operations hostfs_iops = {
898 .create = hostfs_create,
899 .link = hostfs_link,
900 .unlink = hostfs_unlink,
901 .symlink = hostfs_symlink,
902 .mkdir = hostfs_mkdir,
903 .rmdir = hostfs_rmdir,
904 .mknod = hostfs_mknod,
905 .rename = hostfs_rename,
906 .truncate = hostfs_truncate,
907 .permission = hostfs_permission,
908 .setattr = hostfs_setattr,
909 .getattr = hostfs_getattr,
910};
911
912static struct inode_operations hostfs_dir_iops = {
913 .create = hostfs_create,
914 .lookup = hostfs_lookup,
915 .link = hostfs_link,
916 .unlink = hostfs_unlink,
917 .symlink = hostfs_symlink,
918 .mkdir = hostfs_mkdir,
919 .rmdir = hostfs_rmdir,
920 .mknod = hostfs_mknod,
921 .rename = hostfs_rename,
922 .truncate = hostfs_truncate,
923 .permission = hostfs_permission,
924 .setattr = hostfs_setattr,
925 .getattr = hostfs_getattr,
926};
927
928int hostfs_link_readpage(struct file *file, struct page *page)
929{
930 char *buffer, *name;
931 long long start;
932 int err;
933
934 start = page->index << PAGE_CACHE_SHIFT;
935 buffer = kmap(page);
936 name = inode_name(page->mapping->host, 0);
937 if(name == NULL) return(-ENOMEM);
938 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
939 kfree(name);
940 if(err == PAGE_CACHE_SIZE)
941 err = -E2BIG;
942 else if(err > 0){
943 flush_dcache_page(page);
944 SetPageUptodate(page);
945 if (PageError(page)) ClearPageError(page);
946 err = 0;
947 }
948 kunmap(page);
949 unlock_page(page);
950 return(err);
951}
952
953static struct address_space_operations hostfs_link_aops = {
954 .readpage = hostfs_link_readpage,
955};
956
957static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
958{
959 struct inode *root_inode;
960 char *name, *data = d;
961 int err;
962
963 sb->s_blocksize = 1024;
964 sb->s_blocksize_bits = 10;
965 sb->s_magic = HOSTFS_SUPER_MAGIC;
966 sb->s_op = &hostfs_sbops;
967
968 if((data == NULL) || (*data == '\0'))
969 data = root_ino;
970
971 err = -ENOMEM;
972 name = kmalloc(strlen(data) + 1, GFP_KERNEL);
973 if(name == NULL)
974 goto out;
975
976 strcpy(name, data);
977
978 root_inode = iget(sb, 0);
979 if(root_inode == NULL)
980 goto out_free;
981
982 err = init_inode(root_inode, NULL);
983 if(err)
984 goto out_put;
985
986 HOSTFS_I(root_inode)->host_filename = name;
987
988 err = -ENOMEM;
989 sb->s_root = d_alloc_root(root_inode);
990 if(sb->s_root == NULL)
991 goto out_put;
992
993 err = read_inode(root_inode);
994 if(err)
995 goto out_put;
996
997 return(0);
998
999 out_put:
1000 iput(root_inode);
1001 out_free:
1002 kfree(name);
1003 out:
1004 return(err);
1005}
1006
1007static struct super_block *hostfs_read_sb(struct file_system_type *type,
1008 int flags, const char *dev_name,
1009 void *data)
1010{
1011 return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common));
1012}
1013
1014static struct file_system_type hostfs_type = {
1015 .owner = THIS_MODULE,
1016 .name = "hostfs",
1017 .get_sb = hostfs_read_sb,
1018 .kill_sb = kill_anon_super,
1019 .fs_flags = 0,
1020};
1021
1022static int __init init_hostfs(void)
1023{
1024 return(register_filesystem(&hostfs_type));
1025}
1026
1027static void __exit exit_hostfs(void)
1028{
1029 unregister_filesystem(&hostfs_type);
1030}
1031
1032module_init(init_hostfs)
1033module_exit(exit_hostfs)
1034MODULE_LICENSE("GPL");
1035
1036/*
1037 * Overrides for Emacs so that we follow Linus's tabbing style.
1038 * Emacs will notice this stuff at the end of the file and automatically
1039 * adjust the settings for this buffer only. This must remain at the end
1040 * of the file.
1041 * ---------------------------------------------------------------------------
1042 * Local variables:
1043 * c-file-style: "linux"
1044 * End:
1045 */
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
new file mode 100644
index 00000000000..4796e8490f7
--- /dev/null
+++ b/fs/hostfs/hostfs_user.c
@@ -0,0 +1,362 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdio.h>
8#include <fcntl.h>
9#include <dirent.h>
10#include <errno.h>
11#include <utime.h>
12#include <string.h>
13#include <sys/stat.h>
14#include <sys/time.h>
15#include <sys/vfs.h>
16#include "hostfs.h"
17#include "kern_util.h"
18#include "user.h"
19
20int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
21 int *nlink_out, int *uid_out, int *gid_out,
22 unsigned long long *size_out, struct timespec *atime_out,
23 struct timespec *mtime_out, struct timespec *ctime_out,
24 int *blksize_out, unsigned long long *blocks_out)
25{
26 struct stat64 buf;
27
28 if(lstat64(path, &buf) < 0)
29 return(-errno);
30
31 if(inode_out != NULL) *inode_out = buf.st_ino;
32 if(mode_out != NULL) *mode_out = buf.st_mode;
33 if(nlink_out != NULL) *nlink_out = buf.st_nlink;
34 if(uid_out != NULL) *uid_out = buf.st_uid;
35 if(gid_out != NULL) *gid_out = buf.st_gid;
36 if(size_out != NULL) *size_out = buf.st_size;
37 if(atime_out != NULL) {
38 atime_out->tv_sec = buf.st_atime;
39 atime_out->tv_nsec = 0;
40 }
41 if(mtime_out != NULL) {
42 mtime_out->tv_sec = buf.st_mtime;
43 mtime_out->tv_nsec = 0;
44 }
45 if(ctime_out != NULL) {
46 ctime_out->tv_sec = buf.st_ctime;
47 ctime_out->tv_nsec = 0;
48 }
49 if(blksize_out != NULL) *blksize_out = buf.st_blksize;
50 if(blocks_out != NULL) *blocks_out = buf.st_blocks;
51 return(0);
52}
53
54int file_type(const char *path, int *maj, int *min)
55{
56 struct stat64 buf;
57
58 if(lstat64(path, &buf) < 0)
59 return(-errno);
60 /*We cannot pass rdev as is because glibc and the kernel disagree
61 *about its definition.*/
62 if(maj != NULL)
63 *maj = major(buf.st_rdev);
64 if(min != NULL)
65 *min = minor(buf.st_rdev);
66
67 if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
68 else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
69 else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
70 else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
71 else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
72 else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
73 else return(OS_TYPE_FILE);
74}
75
76int access_file(char *path, int r, int w, int x)
77{
78 int mode = 0;
79
80 if(r) mode = R_OK;
81 if(w) mode |= W_OK;
82 if(x) mode |= X_OK;
83 if(access(path, mode) != 0) return(-errno);
84 else return(0);
85}
86
87int open_file(char *path, int r, int w, int append)
88{
89 int mode = 0, fd;
90
91 if(r && !w)
92 mode = O_RDONLY;
93 else if(!r && w)
94 mode = O_WRONLY;
95 else if(r && w)
96 mode = O_RDWR;
97 else panic("Impossible mode in open_file");
98
99 if(append)
100 mode |= O_APPEND;
101 fd = open64(path, mode);
102 if(fd < 0) return(-errno);
103 else return(fd);
104}
105
106void *open_dir(char *path, int *err_out)
107{
108 DIR *dir;
109
110 dir = opendir(path);
111 *err_out = errno;
112 if(dir == NULL) return(NULL);
113 return(dir);
114}
115
116char *read_dir(void *stream, unsigned long long *pos,
117 unsigned long long *ino_out, int *len_out)
118{
119 DIR *dir = stream;
120 struct dirent *ent;
121
122 seekdir(dir, *pos);
123 ent = readdir(dir);
124 if(ent == NULL) return(NULL);
125 *len_out = strlen(ent->d_name);
126 *ino_out = ent->d_ino;
127 *pos = telldir(dir);
128 return(ent->d_name);
129}
130
131int read_file(int fd, unsigned long long *offset, char *buf, int len)
132{
133 int n;
134
135 n = pread64(fd, buf, len, *offset);
136 if(n < 0) return(-errno);
137 *offset += n;
138 return(n);
139}
140
141int write_file(int fd, unsigned long long *offset, const char *buf, int len)
142{
143 int n;
144
145 n = pwrite64(fd, buf, len, *offset);
146 if(n < 0) return(-errno);
147 *offset += n;
148 return(n);
149}
150
151int lseek_file(int fd, long long offset, int whence)
152{
153 int ret;
154
155 ret = lseek64(fd, offset, whence);
156 if(ret < 0) return(-errno);
157 return(0);
158}
159
160void close_file(void *stream)
161{
162 close(*((int *) stream));
163}
164
165void close_dir(void *stream)
166{
167 closedir(stream);
168}
169
170int file_create(char *name, int ur, int uw, int ux, int gr,
171 int gw, int gx, int or, int ow, int ox)
172{
173 int mode, fd;
174
175 mode = 0;
176 mode |= ur ? S_IRUSR : 0;
177 mode |= uw ? S_IWUSR : 0;
178 mode |= ux ? S_IXUSR : 0;
179 mode |= gr ? S_IRGRP : 0;
180 mode |= gw ? S_IWGRP : 0;
181 mode |= gx ? S_IXGRP : 0;
182 mode |= or ? S_IROTH : 0;
183 mode |= ow ? S_IWOTH : 0;
184 mode |= ox ? S_IXOTH : 0;
185 fd = open64(name, O_CREAT | O_RDWR, mode);
186 if(fd < 0)
187 return(-errno);
188 return(fd);
189}
190
191int set_attr(const char *file, struct hostfs_iattr *attrs)
192{
193 struct utimbuf buf;
194 int err, ma;
195
196 if(attrs->ia_valid & HOSTFS_ATTR_MODE){
197 if(chmod(file, attrs->ia_mode) != 0) return(-errno);
198 }
199 if(attrs->ia_valid & HOSTFS_ATTR_UID){
200 if(chown(file, attrs->ia_uid, -1)) return(-errno);
201 }
202 if(attrs->ia_valid & HOSTFS_ATTR_GID){
203 if(chown(file, -1, attrs->ia_gid)) return(-errno);
204 }
205 if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
206 if(truncate(file, attrs->ia_size)) return(-errno);
207 }
208 ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
209 if((attrs->ia_valid & ma) == ma){
210 buf.actime = attrs->ia_atime.tv_sec;
211 buf.modtime = attrs->ia_mtime.tv_sec;
212 if(utime(file, &buf) != 0) return(-errno);
213 }
214 else {
215 struct timespec ts;
216
217 if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
218 err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
219 NULL, NULL, &ts, NULL, NULL, NULL);
220 if(err != 0)
221 return(err);
222 buf.actime = attrs->ia_atime.tv_sec;
223 buf.modtime = ts.tv_sec;
224 if(utime(file, &buf) != 0)
225 return(-errno);
226 }
227 if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
228 err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
229 NULL, &ts, NULL, NULL, NULL, NULL);
230 if(err != 0)
231 return(err);
232 buf.actime = ts.tv_sec;
233 buf.modtime = attrs->ia_mtime.tv_sec;
234 if(utime(file, &buf) != 0)
235 return(-errno);
236 }
237 }
238 if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
239 if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
240 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
241 &attrs->ia_atime, &attrs->ia_mtime, NULL,
242 NULL, NULL);
243 if(err != 0) return(err);
244 }
245 return(0);
246}
247
248int make_symlink(const char *from, const char *to)
249{
250 int err;
251
252 err = symlink(to, from);
253 if(err) return(-errno);
254 return(0);
255}
256
257int unlink_file(const char *file)
258{
259 int err;
260
261 err = unlink(file);
262 if(err) return(-errno);
263 return(0);
264}
265
266int do_mkdir(const char *file, int mode)
267{
268 int err;
269
270 err = mkdir(file, mode);
271 if(err) return(-errno);
272 return(0);
273}
274
275int do_rmdir(const char *file)
276{
277 int err;
278
279 err = rmdir(file);
280 if(err) return(-errno);
281 return(0);
282}
283
284int do_mknod(const char *file, int mode, int dev)
285{
286 int err;
287
288 err = mknod(file, mode, dev);
289 if(err) return(-errno);
290 return(0);
291}
292
293int link_file(const char *to, const char *from)
294{
295 int err;
296
297 err = link(to, from);
298 if(err) return(-errno);
299 return(0);
300}
301
302int do_readlink(char *file, char *buf, int size)
303{
304 int n;
305
306 n = readlink(file, buf, size);
307 if(n < 0)
308 return(-errno);
309 if(n < size)
310 buf[n] = '\0';
311 return(n);
312}
313
314int rename_file(char *from, char *to)
315{
316 int err;
317
318 err = rename(from, to);
319 if(err < 0) return(-errno);
320 return(0);
321}
322
323int do_statfs(char *root, long *bsize_out, long long *blocks_out,
324 long long *bfree_out, long long *bavail_out,
325 long long *files_out, long long *ffree_out,
326 void *fsid_out, int fsid_size, long *namelen_out,
327 long *spare_out)
328{
329 struct statfs64 buf;
330 int err;
331
332 err = statfs64(root, &buf);
333 if(err < 0) return(-errno);
334 *bsize_out = buf.f_bsize;
335 *blocks_out = buf.f_blocks;
336 *bfree_out = buf.f_bfree;
337 *bavail_out = buf.f_bavail;
338 *files_out = buf.f_files;
339 *ffree_out = buf.f_ffree;
340 memcpy(fsid_out, &buf.f_fsid,
341 sizeof(buf.f_fsid) > fsid_size ? fsid_size :
342 sizeof(buf.f_fsid));
343 *namelen_out = buf.f_namelen;
344 spare_out[0] = buf.f_spare[0];
345 spare_out[1] = buf.f_spare[1];
346 spare_out[2] = buf.f_spare[2];
347 spare_out[3] = buf.f_spare[3];
348 spare_out[4] = buf.f_spare[4];
349 spare_out[5] = buf.f_spare[5];
350 return(0);
351}
352
353/*
354 * Overrides for Emacs so that we follow Linus's tabbing style.
355 * Emacs will notice this stuff at the end of the file and automatically
356 * adjust the settings for this buffer only. This must remain at the end
357 * of the file.
358 * ---------------------------------------------------------------------------
359 * Local variables:
360 * c-file-style: "linux"
361 * End:
362 */