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