1 /*
2 * linux/fs/sysv/dir.c
3 *
4 * minix/dir.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * coh/dir.c
8 * Copyright (C) 1993 Pascal Haible, Bruno Haible
9 *
10 * sysv/dir.c
11 * Copyright (C) 1993 Bruno Haible
12 *
13 * SystemV/Coherent directory handling functions
14 */
15
16 #include <linux/fs.h>
17 #include <linux/sysv_fs.h>
18 #include <linux/pagemap.h>
19
20 static int sysv_readdir(struct file *, void *, filldir_t);
21
22 struct file_operations sysv_dir_operations = {
23 read: generic_read_dir,
24 readdir: sysv_readdir,
25 fsync: sysv_sync_file,
26 };
27
dir_put_page(struct page * page)28 static inline void dir_put_page(struct page *page)
29 {
30 kunmap(page);
31 page_cache_release(page);
32 }
33
dir_pages(struct inode * inode)34 static inline unsigned long dir_pages(struct inode *inode)
35 {
36 return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
37 }
38
dir_commit_chunk(struct page * page,unsigned from,unsigned to)39 static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
40 {
41 struct inode *dir = (struct inode *)page->mapping->host;
42 int err = 0;
43
44 dir->i_version = ++event;
45 page->mapping->a_ops->commit_write(NULL, page, from, to);
46 if (IS_SYNC(dir)) {
47 int err2;
48 err = writeout_one_page(page);
49 err2 = waitfor_one_page(page);
50 if (err == 0)
51 err = err2;
52 }
53 return err;
54 }
55
dir_get_page(struct inode * dir,unsigned long n)56 static struct page * dir_get_page(struct inode *dir, unsigned long n)
57 {
58 struct address_space *mapping = dir->i_mapping;
59 struct page *page = read_cache_page(mapping, n,
60 (filler_t*)mapping->a_ops->readpage, NULL);
61 if (!IS_ERR(page)) {
62 wait_on_page(page);
63 kmap(page);
64 if (!Page_Uptodate(page))
65 goto fail;
66 }
67 return page;
68
69 fail:
70 dir_put_page(page);
71 return ERR_PTR(-EIO);
72 }
73
sysv_readdir(struct file * filp,void * dirent,filldir_t filldir)74 static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
75 {
76 unsigned long pos = filp->f_pos;
77 struct inode *inode = filp->f_dentry->d_inode;
78 struct super_block *sb = inode->i_sb;
79 unsigned offset = pos & ~PAGE_CACHE_MASK;
80 unsigned long n = pos >> PAGE_CACHE_SHIFT;
81 unsigned long npages = dir_pages(inode);
82
83 pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
84 if (pos >= inode->i_size)
85 goto done;
86
87 for ( ; n < npages; n++, offset = 0) {
88 char *kaddr, *limit;
89 struct sysv_dir_entry *de;
90 struct page *page = dir_get_page(inode, n);
91
92 if (IS_ERR(page))
93 continue;
94 kaddr = (char *)page_address(page);
95 de = (struct sysv_dir_entry *)(kaddr+offset);
96 limit = kaddr + PAGE_CACHE_SIZE - SYSV_DIRSIZE;
97 for ( ;(char*)de <= limit; de++) {
98 char *name = de->name;
99 int over;
100
101 if (!de->inode)
102 continue;
103
104 offset = (char *)de - kaddr;
105
106 over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN),
107 (n<<PAGE_CACHE_SHIFT) | offset,
108 fs16_to_cpu(sb, de->inode), DT_UNKNOWN);
109 if (over) {
110 dir_put_page(page);
111 goto done;
112 }
113 }
114 dir_put_page(page);
115 }
116
117 done:
118 filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
119 filp->f_version = inode->i_version;
120 UPDATE_ATIME(inode);
121 return 0;
122 }
123
124 /* compare strings: name[0..len-1] (not zero-terminated) and
125 * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
126 */
namecompare(int len,int maxlen,const char * name,const char * buffer)127 static inline int namecompare(int len, int maxlen,
128 const char * name, const char * buffer)
129 {
130 if (len < maxlen && buffer[len])
131 return 0;
132 return !memcmp(name, buffer, len);
133 }
134
135 /*
136 * sysv_find_entry()
137 *
138 * finds an entry in the specified directory with the wanted name. It
139 * returns the cache buffer in which the entry was found, and the entry
140 * itself (as a parameter - res_dir). It does NOT read the inode of the
141 * entry - you'll have to do that yourself if you want to.
142 */
sysv_find_entry(struct dentry * dentry,struct page ** res_page)143 struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page)
144 {
145 const char * name = dentry->d_name.name;
146 int namelen = dentry->d_name.len;
147 struct inode * dir = dentry->d_parent->d_inode;
148 unsigned long start, n;
149 unsigned long npages = dir_pages(dir);
150 struct page *page = NULL;
151 struct sysv_dir_entry *de;
152
153 *res_page = NULL;
154
155 start = dir->u.sysv_i.i_dir_start_lookup;
156 if (start >= npages)
157 start = 0;
158 n = start;
159
160 do {
161 char *kaddr;
162 page = dir_get_page(dir, n);
163 if (!IS_ERR(page)) {
164 kaddr = (char*)page_address(page);
165 de = (struct sysv_dir_entry *) kaddr;
166 kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
167 for ( ; (char *) de <= kaddr ; de++) {
168 if (!de->inode)
169 continue;
170 if (namecompare(namelen, SYSV_NAMELEN,
171 name, de->name))
172 goto found;
173 }
174 }
175 dir_put_page(page);
176
177 if (++n >= npages)
178 n = 0;
179 } while (n != start);
180
181 return NULL;
182
183 found:
184 dir->u.sysv_i.i_dir_start_lookup = n;
185 *res_page = page;
186 return de;
187 }
188
sysv_add_link(struct dentry * dentry,struct inode * inode)189 int sysv_add_link(struct dentry *dentry, struct inode *inode)
190 {
191 struct inode *dir = dentry->d_parent->d_inode;
192 const char * name = dentry->d_name.name;
193 int namelen = dentry->d_name.len;
194 struct page *page = NULL;
195 struct sysv_dir_entry * de;
196 unsigned long npages = dir_pages(dir);
197 unsigned long n;
198 char *kaddr;
199 unsigned from, to;
200 int err;
201
202 /* We take care of directory expansion in the same loop */
203 for (n = 0; n <= npages; n++) {
204 page = dir_get_page(dir, n);
205 err = PTR_ERR(page);
206 if (IS_ERR(page))
207 goto out;
208 kaddr = (char*)page_address(page);
209 de = (struct sysv_dir_entry *)kaddr;
210 kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
211 while ((char *)de <= kaddr) {
212 if (!de->inode)
213 goto got_it;
214 err = -EEXIST;
215 if (namecompare(namelen, SYSV_NAMELEN, name, de->name))
216 goto out_page;
217 de++;
218 }
219 dir_put_page(page);
220 }
221 BUG();
222 return -EINVAL;
223
224 got_it:
225 from = (char*)de - (char*)page_address(page);
226 to = from + SYSV_DIRSIZE;
227 lock_page(page);
228 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
229 if (err)
230 goto out_unlock;
231 memcpy (de->name, name, namelen);
232 memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
233 de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
234 err = dir_commit_chunk(page, from, to);
235 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
236 mark_inode_dirty(dir);
237 out_unlock:
238 UnlockPage(page);
239 out_page:
240 dir_put_page(page);
241 out:
242 return err;
243 }
244
sysv_delete_entry(struct sysv_dir_entry * de,struct page * page)245 int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
246 {
247 struct address_space *mapping = page->mapping;
248 struct inode *inode = (struct inode*)mapping->host;
249 char *kaddr = (char*)page_address(page);
250 unsigned from = (char*)de - kaddr;
251 unsigned to = from + SYSV_DIRSIZE;
252 int err;
253
254 lock_page(page);
255 err = mapping->a_ops->prepare_write(NULL, page, from, to);
256 if (err)
257 BUG();
258 de->inode = 0;
259 err = dir_commit_chunk(page, from, to);
260 UnlockPage(page);
261 dir_put_page(page);
262 inode->i_ctime = inode->i_mtime = CURRENT_TIME;
263 mark_inode_dirty(inode);
264 return err;
265 }
266
sysv_make_empty(struct inode * inode,struct inode * dir)267 int sysv_make_empty(struct inode *inode, struct inode *dir)
268 {
269 struct address_space *mapping = inode->i_mapping;
270 struct page *page = grab_cache_page(mapping, 0);
271 struct sysv_dir_entry * de;
272 char *base;
273 int err;
274
275 if (!page)
276 return -ENOMEM;
277 err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE);
278 if (err)
279 goto fail;
280
281 base = (char*)page_address(page);
282 memset(base, 0, PAGE_CACHE_SIZE);
283
284 de = (struct sysv_dir_entry *) base;
285 de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
286 strcpy(de->name,".");
287 de++;
288 de->inode = cpu_to_fs16(inode->i_sb, dir->i_ino);
289 strcpy(de->name,"..");
290
291 err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE);
292 fail:
293 UnlockPage(page);
294 page_cache_release(page);
295 return err;
296 }
297
298 /*
299 * routine to check that the specified directory is empty (for rmdir)
300 */
sysv_empty_dir(struct inode * inode)301 int sysv_empty_dir(struct inode * inode)
302 {
303 struct super_block *sb = inode->i_sb;
304 struct page *page = NULL;
305 unsigned long i, npages = dir_pages(inode);
306
307 for (i = 0; i < npages; i++) {
308 char *kaddr;
309 struct sysv_dir_entry * de;
310 page = dir_get_page(inode, i);
311
312 if (IS_ERR(page))
313 continue;
314
315 kaddr = (char *)page_address(page);
316 de = (struct sysv_dir_entry *)kaddr;
317 kaddr += PAGE_CACHE_SIZE-SYSV_DIRSIZE;
318
319 for ( ;(char *)de <= kaddr; de++) {
320 if (!de->inode)
321 continue;
322 /* check for . and .. */
323 if (de->name[0] != '.')
324 goto not_empty;
325 if (!de->name[1]) {
326 if (de->inode == cpu_to_fs16(sb, inode->i_ino))
327 continue;
328 goto not_empty;
329 }
330 if (de->name[1] != '.' || de->name[2])
331 goto not_empty;
332 }
333 dir_put_page(page);
334 }
335 return 1;
336
337 not_empty:
338 dir_put_page(page);
339 return 0;
340 }
341
342 /* Releases the page */
sysv_set_link(struct sysv_dir_entry * de,struct page * page,struct inode * inode)343 void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
344 struct inode *inode)
345 {
346 struct inode *dir = (struct inode*)page->mapping->host;
347 unsigned from = (char *)de-(char*)page_address(page);
348 unsigned to = from + SYSV_DIRSIZE;
349 int err;
350
351 lock_page(page);
352 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
353 if (err)
354 BUG();
355 de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
356 err = dir_commit_chunk(page, from, to);
357 UnlockPage(page);
358 dir_put_page(page);
359 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
360 mark_inode_dirty(dir);
361 }
362
sysv_dotdot(struct inode * dir,struct page ** p)363 struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p)
364 {
365 struct page *page = dir_get_page(dir, 0);
366 struct sysv_dir_entry *de = NULL;
367
368 if (!IS_ERR(page)) {
369 de = (struct sysv_dir_entry*) page_address(page) + 1;
370 *p = page;
371 }
372 return de;
373 }
374
sysv_inode_by_name(struct dentry * dentry)375 ino_t sysv_inode_by_name(struct dentry *dentry)
376 {
377 struct page *page;
378 struct sysv_dir_entry *de = sysv_find_entry (dentry, &page);
379 ino_t res = 0;
380
381 if (de) {
382 res = fs16_to_cpu(dentry->d_sb, de->inode);
383 dir_put_page(page);
384 }
385 return res;
386 }
387