File: /usr/src/linux/arch/parisc/hpux/fs.c

1     /*
2      * linux/arch/parisc/kernel/sys_hpux.c
3      *
4      * implements HPUX syscalls.
5      */
6     
7     #include <linux/mm.h>
8     #include <linux/sched.h>
9     #include <linux/file.h>
10     #include <linux/smp_lock.h>
11     #include <linux/slab.h>
12     #include <asm/errno.h>
13     #include <asm/uaccess.h>
14     
15     int hpux_execve(struct pt_regs *regs)
16     {
17     	int error;
18     	char *filename;
19     
20     	filename = getname((char *) regs->gr[26]);
21     	error = PTR_ERR(filename);
22     	if (IS_ERR(filename))
23     		goto out;
24     
25     	error = do_execve(filename, (char **) regs->gr[25],
26     		(char **)regs->gr[24], regs);
27     
28     	if (error == 0)
29     		current->ptrace &= ~PT_DTRACE;
30     	putname(filename);
31     
32     out:
33     	return error;
34     }
35     
36     struct hpux_dirent {
37     	long	d_off_pad; /* we only have a 32-bit off_t */
38     	long	d_off;
39     	ino_t	d_ino;
40     	short	d_reclen;
41     	short	d_namlen;
42     	char	d_name[1];
43     };
44     
45     struct getdents_callback {
46     	struct hpux_dirent *current_dir;
47     	struct hpux_dirent *previous;
48     	int count;
49     	int error;
50     };
51     
52     #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
53     #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
54     
55     static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino)
56     {
57     	struct hpux_dirent * dirent;
58     	struct getdents_callback * buf = (struct getdents_callback *) __buf;
59     	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
60     
61     	buf->error = -EINVAL;	/* only used if we fail.. */
62     	if (reclen > buf->count)
63     		return -EINVAL;
64     	dirent = buf->previous;
65     	if (dirent)
66     		put_user(offset, &dirent->d_off);
67     	dirent = buf->current_dir;
68     	buf->previous = dirent;
69     	put_user(ino, &dirent->d_ino);
70     	put_user(reclen, &dirent->d_reclen);
71     	put_user(namlen, &dirent->d_namlen);
72     	copy_to_user(dirent->d_name, name, namlen);
73     	put_user(0, dirent->d_name + namlen);
74     	((char *) dirent) += reclen;
75     	buf->current_dir = dirent;
76     	buf->count -= reclen;
77     	return 0;
78     }
79     
80     #undef NAME_OFFSET
81     #undef ROUND_UP
82     
83     int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
84     {
85     	struct file * file;
86     	struct dentry * dentry;
87     	struct inode * inode;
88     	struct hpux_dirent * lastdirent;
89     	struct getdents_callback buf;
90     	int error;
91     
92     	lock_kernel();
93     	error = -EBADF;
94     	file = fget(fd);
95     	if (!file)
96     		goto out;
97     
98     	dentry = file->f_dentry;
99     	if (!dentry)
100     		goto out_putf;
101     
102     	inode = dentry->d_inode;
103     	if (!inode)
104     		goto out_putf;
105     
106     	buf.current_dir = dirent;
107     	buf.previous = NULL;
108     	buf.count = count;
109     	buf.error = 0;
110     
111     	error = -ENOTDIR;
112     	if (!file->f_op || !file->f_op->readdir)
113     		goto out_putf;
114     
115     	/*
116     	 * Get the inode's semaphore to prevent changes
117     	 * to the directory while we read it.
118     	 */
119     	down(&inode->i_sem);
120     	error = file->f_op->readdir(file, &buf, filldir);
121     	up(&inode->i_sem);
122     	if (error < 0)
123     		goto out_putf;
124     	error = buf.error;
125     	lastdirent = buf.previous;
126     	if (lastdirent) {
127     		put_user(file->f_pos, &lastdirent->d_off);
128     		error = count - buf.count;
129     	}
130     
131     out_putf:
132     	fput(file);
133     out:
134     	unlock_kernel();
135     	return error;
136     }
137     
138     int hpux_mount(const char *fs, const char *path, int mflag,
139     		const char *fstype, const char *dataptr, int datalen)
140     {
141     	return -ENOSYS;
142     }
143     
144     static int cp_hpux_stat(struct inode * inode, struct hpux_stat64 * statbuf)
145     {
146     	struct hpux_stat64 tmp;
147     	unsigned int blocks, indirect;
148     
149     	memset(&tmp, 0, sizeof(tmp));
150     	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
151     	tmp.st_ino = inode->i_ino;
152     	tmp.st_mode = inode->i_mode;
153     	tmp.st_nlink = inode->i_nlink;
154     	tmp.st_uid = inode->i_uid;
155     	tmp.st_gid = inode->i_gid;
156     	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
157     	tmp.st_size = inode->i_size;
158     	tmp.st_atime = inode->i_atime;
159     	tmp.st_mtime = inode->i_mtime;
160     	tmp.st_ctime = inode->i_ctime;
161     
162     #define D_B   7
163     #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
164     
165     	if (!inode->i_blksize) {
166     		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
167     		if (blocks > D_B) {
168     			indirect = (blocks - D_B + I_B - 1) / I_B;
169     			blocks += indirect;
170     			if (indirect > 1) {
171     				indirect = (indirect - 1 + I_B - 1) / I_B;
172     				blocks += indirect;
173     				if (indirect > 1)
174     					blocks++;
175     			}
176     		}
177     		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
178     		tmp.st_blksize = BLOCK_SIZE;
179     	} else {
180     		tmp.st_blocks = inode->i_blocks;
181     		tmp.st_blksize = inode->i_blksize;
182     	}
183     	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
184     }
185     
186     /*
187      * Revalidate the inode. This is required for proper NFS attribute caching.
188      * Blatently copied wholesale from fs/stat.c
189      */
190     static __inline__ int
191     do_revalidate(struct dentry *dentry)
192     {
193     	struct inode * inode = dentry->d_inode;
194     	if (inode->i_op && inode->i_op->revalidate)
195     		return inode->i_op->revalidate(dentry);
196     	return 0;
197     }
198     
199     long hpux_stat64(const char *path, struct hpux_stat64 *buf)
200     {
201     	struct nameidata nd;
202     	int error;
203     
204     	lock_kernel();
205     	error = user_path_walk(path, &nd);
206     	if (!error) {
207     		error = do_revalidate(nd.dentry);
208     		if (!error)
209     			error = cp_hpux_stat(nd.dentry->d_inode, buf);
210     		path_release(&nd);
211     	}
212     	unlock_kernel();
213     	return error;
214     }
215     
216     long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
217     {
218     	struct file * f;
219     	int err = -EBADF;
220     
221     	lock_kernel();
222     	f = fget(fd);
223     	if (f) {
224     		struct dentry * dentry = f->f_dentry;
225     
226     		err = do_revalidate(dentry);
227     		if (!err)
228     			err = cp_hpux_stat(dentry->d_inode, statbuf);
229     		fput(f);
230     	}
231     	unlock_kernel();
232     	return err;
233     }
234     
235     long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf)
236     {
237     	struct nameidata nd;
238     	int error;
239     
240     	lock_kernel();
241     	error = user_path_walk_link(filename, &nd);
242     	if (!error) {
243     		error = do_revalidate(nd.dentry);
244     		if (!error)
245     			error = cp_hpux_stat(nd.dentry->d_inode, statbuf);
246     		path_release(&nd);
247     	}
248     	unlock_kernel();
249     	return error;
250     }
251