Import 2.3.1pre2
[davej-history.git] / fs / proc / omirr.c
blobdbf2b32b979e8c91465312dee67172054569148f
1 /*
2 * fs/proc/omirr.c - online mirror support
4 * (C) 1997 Thomas Schoebel-Theuer
5 */
7 #include <linux/string.h>
8 #include <linux/mm.h>
9 #include <linux/fs.h>
10 #include <linux/omirr.h>
11 #include <asm/uaccess.h>
13 static int nr_omirr_open = 0;
14 static int cleared_flag = 0;
16 static char * buffer = NULL;
17 static int read_pos, write_pos;
18 static int clip_pos, max_pos;
19 static DECLARE_WAIT_QUEUE_HEAD(read_wait);
20 static DECLARE_WAIT_QUEUE_HEAD(write_wait);
22 static /*inline*/ int reserve_write_space(int len)
24 int rest = max_pos - write_pos;
26 if(rest < len) {
27 clip_pos = write_pos;
28 write_pos = 0;
29 rest = max_pos;
31 while(read_pos > write_pos && read_pos <= write_pos+len) {
32 if(!nr_omirr_open)
33 return 0;
34 interruptible_sleep_on(&write_wait);
36 return 1;
39 static /*inline*/ void write_space(int len)
41 write_pos += len;
42 wake_up_interruptible(&read_wait);
45 static /*inline*/ int reserve_read_space(int len)
47 int rest = clip_pos - read_pos;
49 if(!rest) {
50 read_pos = 0;
51 rest = clip_pos;
52 clip_pos = max_pos;
54 if(len > rest)
55 len = rest;
56 while(read_pos == write_pos) {
57 interruptible_sleep_on(&read_wait);
59 rest = write_pos - read_pos;
60 if(rest > 0 && rest < len)
61 len = rest;
62 return len;
65 static /*inline*/ void read_space(int len)
67 read_pos += len;
68 if(read_pos >= clip_pos) {
69 read_pos = 0;
70 clip_pos = max_pos;
72 wake_up_interruptible(&write_wait);
75 static /*inline*/ void init_buffer(char * initxt)
77 int len = initxt ? strlen(initxt) : 0;
79 if(!buffer) {
80 buffer = (char*)__get_free_page(GFP_USER);
81 max_pos = clip_pos = PAGE_SIZE;
83 read_pos = write_pos = 0;
84 memcpy(buffer, initxt, len);
85 write_space(len);
88 static int omirr_open(struct inode * inode, struct file * file)
90 if(nr_omirr_open)
91 return -EAGAIN;
92 nr_omirr_open++;
93 if(!buffer)
94 init_buffer(NULL);
95 return 0;
98 static int omirr_release(struct inode * inode, struct file * file)
100 nr_omirr_open--;
101 read_space(0);
102 return 0;
105 static long omirr_read(struct inode * inode, struct file * file,
106 char * buf, unsigned long count)
108 char * tmp;
109 int len;
110 int error = 0;
112 if(!count)
113 goto done;
114 error = -EINVAL;
115 if(!buf || count < 0)
116 goto done;
118 error = verify_area(VERIFY_WRITE, buf, count);
119 if(error)
120 goto done;
122 error = -EAGAIN;
123 if((file->f_flags & O_NONBLOCK) && read_pos == write_pos)
124 goto done;
126 error = len = reserve_read_space(count);
127 tmp = buffer + read_pos;
128 while(len) {
129 put_user(*tmp++, buf++);
130 len--;
132 read_space(error);
133 done:
134 return error;
137 int compute_name(struct dentry * entry, char * buf)
139 int len;
141 if(IS_ROOT(entry)) {
142 *buf = '/';
143 return 1;
145 len = compute_name(entry->d_parent, buf);
146 if(len > 1) {
147 buf[len++] = '/';
149 memcpy(buf+len, entry->d_name, entry->d_len);
150 return len + entry->d_len;
153 int _omirr_print(struct dentry * ent1, struct dentry * ent2,
154 struct qstr * suffix, const char * fmt,
155 va_list args1, va_list args2)
157 int count = strlen(fmt) + 10; /* estimate */
158 const char * tmp = fmt;
159 char lenbuf[8];
160 int res;
162 if(!buffer)
163 init_buffer(NULL);
164 while(*tmp) {
165 while(*tmp && *tmp++ != '%') ;
166 if(*tmp) {
167 if(*tmp == 's') {
168 char * str = va_arg(args1, char*);
169 count += strlen(str);
170 } else {
171 (void)va_arg(args1, int);
172 count += 8; /* estimate */
176 if(ent1) {
177 struct dentry * dent = ent1;
178 while(dent && !IS_ROOT(dent)) {
179 count += dent->d_len + 1;
180 dent = dent->d_parent;
182 count++;
183 if(ent2) {
184 dent = ent2;
185 while(dent && !IS_ROOT(dent)) {
186 count += dent->d_len + 1;
187 dent = dent->d_parent;
189 count++;
191 if(suffix)
192 count += suffix->len + 1;
195 if((nr_omirr_open | cleared_flag) && reserve_write_space(count)) {
196 cleared_flag = 0;
197 res = vsprintf(buffer+write_pos+4, fmt, args2) + 4;
198 if(res > count)
199 printk("omirr: format estimate was wrong\n");
200 if(ent1) {
201 res += compute_name(ent1, buffer+write_pos+res);
202 if(ent2) {
203 buffer[write_pos+res++] = '\0';
204 res += compute_name(ent2, buffer+write_pos+res);
206 if(suffix) {
207 buffer[write_pos+res++] = '/';
208 memcpy(buffer+write_pos+res,
209 suffix->name, suffix->len);
210 res += suffix->len;
212 buffer[write_pos+res++] = '\0';
213 buffer[write_pos+res++] = '\n';
215 sprintf(lenbuf, "%04d", res);
216 memcpy(buffer+write_pos, lenbuf, 4);
217 } else {
218 if(!cleared_flag) {
219 cleared_flag = 1;
220 init_buffer("0007 Z\n");
222 res = 0;
224 write_space(res);
225 return res;
228 int omirr_print(struct dentry * ent1, struct dentry * ent2,
229 struct qstr * suffix, const char * fmt, ...)
231 va_list args1, args2;
232 int res;
234 /* I don't know whether I could make a simple copy of the va_list,
235 * so for the safe way...
237 va_start(args1, fmt);
238 va_start(args2, fmt);
239 res = _omirr_print(ent1, ent2, suffix, fmt, args1, args2);
240 va_end(args2);
241 va_end(args1);
242 return res;
245 int omirr_printall(struct inode * inode, const char * fmt, ...)
247 int res = 0;
248 struct dentry * tmp = inode->i_dentry;
250 if(tmp) do {
251 va_list args1, args2;
252 va_start(args1, fmt);
253 va_start(args2, fmt);
254 res += _omirr_print(tmp, NULL, NULL, fmt, args1, args2);
255 va_end(args2);
256 va_end(args1);
257 tmp = tmp->d_next;
258 } while(tmp != inode->i_dentry);
259 return res;
262 static struct file_operations omirr_operations = {
263 NULL, /* omirr_lseek */
264 omirr_read,
265 NULL, /* omirr_write */
266 NULL, /* omirr_readdir */
267 NULL, /* omirr_select */
268 NULL, /* omirr_ioctl */
269 NULL, /* mmap */
270 omirr_open,
271 NULL, /* flush */
272 omirr_release,
273 NULL, /* fsync */
274 NULL, /* fasync */
275 NULL, /* check_media_change */
276 NULL /* revalidate */
279 struct inode_operations proc_omirr_inode_operations = {
280 &omirr_operations,
281 NULL, /* create */
282 NULL, /* lookup */
283 NULL, /* link */
284 NULL, /* unlink */
285 NULL, /* symlink */
286 NULL, /* mkdir */
287 NULL, /* rmdir */
288 NULL, /* mknod */
289 NULL, /* rename */
290 NULL, /* readlink */
291 NULL, /* follow_link */
292 NULL, /* readpage */
293 NULL, /* writepage */
294 NULL, /* bmap */
295 NULL, /* truncate */
296 NULL, /* permission */
297 NULL /* smap */