~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/sysv/namei.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/sysv/namei.c
  3  *
  4  *  minix/namei.c
  5  *  Copyright (C) 1991, 1992  Linus Torvalds
  6  *
  7  *  coh/namei.c
  8  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
  9  *
 10  *  sysv/namei.c
 11  *  Copyright (C) 1993  Bruno Haible
 12  *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
 13  */
 14 
 15 
 16 #include <linux/sched.h>
 17 #include <linux/kernel.h>
 18 #include <linux/fs.h>
 19 #include <linux/sysv_fs.h>
 20 #include <linux/string.h>
 21 #include <linux/stat.h>
 22 #include <linux/errno.h>
 23 
 24 /* compare strings: name[0..len-1] (not zero-terminated) and
 25  * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
 26  */
 27 static inline int namecompare(int len, int maxlen,
 28         const char * name, const char * buffer)
 29 {
 30         if (len > maxlen)
 31                 return 0;
 32         if (len < maxlen && buffer[len])
 33                 return 0;
 34         return !memcmp(name, buffer, len);
 35 }
 36 
 37 /*
 38  * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!]
 39  * Thus we'll have to use sysv_match. No big problem. Match also makes
 40  * some sanity tests.
 41  *
 42  * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure.
 43  */
 44 static int sysv_match(int len, const char * name, struct sysv_dir_entry * de)
 45 {
 46         if (!de->inode || len > SYSV_NAMELEN)
 47                 return 0;
 48         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
 49         if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
 50                 return 1;
 51         return namecompare(len, SYSV_NAMELEN, name, de->name);
 52 }
 53 
 54 /*
 55  *      sysv_find_entry()
 56  *
 57  * finds an entry in the specified directory with the wanted name. It
 58  * returns the cache buffer in which the entry was found, and the entry
 59  * itself (as a parameter - res_dir). It does NOT read the inode of the
 60  * entry - you'll have to do that yourself if you want to.
 61  */
 62 static struct buffer_head * sysv_find_entry(struct inode * dir,
 63         const char * name, int namelen, struct sysv_dir_entry ** res_dir)
 64 {
 65         struct super_block * sb;
 66         unsigned long pos, block, offset; /* pos = block * block_size + offset */
 67         struct buffer_head * bh;
 68 
 69         *res_dir = NULL;
 70         sb = dir->i_sb;
 71         if (namelen > SYSV_NAMELEN) {
 72                 if (sb->sv_truncate)
 73                         namelen = SYSV_NAMELEN;
 74                 else
 75                         return NULL;
 76         }
 77         bh = NULL;
 78         pos = block = offset = 0;
 79         while (pos < dir->i_size) {
 80                 if (!bh) {
 81                         bh = sysv_file_bread(dir, block, 0);
 82                         if (!bh) {
 83                                 /* offset = 0; */ block++;
 84                                 pos += sb->sv_block_size;
 85                                 continue;
 86                         }
 87                 }
 88                 if (sysv_match(namelen, name,
 89                                *res_dir = (struct sysv_dir_entry *) (bh->b_data + offset) ))
 90                         return bh;
 91                 pos += SYSV_DIRSIZE;
 92                 offset += SYSV_DIRSIZE;
 93                 if (offset < sb->sv_block_size)
 94                         continue;
 95                 brelse(bh);
 96                 bh = NULL;
 97                 offset = 0; block++;
 98         }
 99         brelse(bh);
100         *res_dir = NULL;
101         return NULL;
102 }
103 
104 static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
105 {
106         struct inode * inode = NULL;
107         struct sysv_dir_entry * de;
108         struct buffer_head * bh;
109 
110         bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
111 
112         if (bh) {
113                 int ino = de->inode;
114                 brelse(bh);
115                 inode = iget(dir->i_sb, ino);
116         
117                 if (!inode) 
118                         return ERR_PTR(-EACCES);
119         }
120         d_add(dentry, inode);
121         return NULL;
122 }
123 
124 /*
125  *      sysv_add_entry()
126  *
127  * adds a file entry to the specified directory, returning a possible
128  * error value if it fails.
129  *
130  * NOTE!! The inode part of 'de' is left at 0 - which means you
131  * may not sleep between calling this and putting something into
132  * the entry, as someone else might have used it while you slept.
133  */
134 static int sysv_add_entry(struct inode * dir,
135         const char * name, int namelen,
136         struct buffer_head ** res_buf,
137         struct sysv_dir_entry ** res_dir)
138 {
139         struct super_block * sb;
140         int i;
141         unsigned long pos, block, offset; /* pos = block * block_size + offset */
142         struct buffer_head * bh;
143         struct sysv_dir_entry * de;
144 
145         *res_buf = NULL;
146         *res_dir = NULL;
147         sb = dir->i_sb;
148         if (namelen > SYSV_NAMELEN) {
149                 if (sb->sv_truncate)
150                         namelen = SYSV_NAMELEN;
151                 else
152                         return -ENAMETOOLONG;
153         }
154         if (!namelen)
155                 return -ENOENT;
156         bh = NULL;
157         pos = block = offset = 0;
158         while (1) {
159                 if (!bh) {
160                         bh = sysv_file_bread(dir, block, 1);
161                         if (!bh)
162                                 return -ENOSPC;
163                 }
164                 de = (struct sysv_dir_entry *) (bh->b_data + offset);
165                 pos += SYSV_DIRSIZE;
166                 offset += SYSV_DIRSIZE;
167                 if (pos > dir->i_size) {
168                         de->inode = 0;
169                         dir->i_size = pos;
170                         mark_inode_dirty(dir);
171                 }
172                 if (de->inode) {
173                         if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
174                                 brelse(bh);
175                                 return -EEXIST;
176                         }
177                 } else {
178                         dir->i_mtime = dir->i_ctime = CURRENT_TIME;
179                         mark_inode_dirty(dir);
180                         for (i = 0; i < SYSV_NAMELEN ; i++)
181                                 de->name[i] = (i < namelen) ? name[i] : 0;
182                         mark_buffer_dirty(bh);
183                         *res_dir = de;
184                         break;
185                 }
186                 if (offset < sb->sv_block_size)
187                         continue;
188                 brelse(bh);
189                 bh = NULL;
190                 offset = 0; block++;
191         }
192         *res_buf = bh;
193         return 0;
194 }
195 
196 static int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
197 {
198         int error;
199         struct inode * inode;
200         struct buffer_head * bh;
201         struct sysv_dir_entry * de;
202 
203         inode = sysv_new_inode(dir);
204         if (!inode) 
205                 return -ENOSPC;
206         inode->i_op = &sysv_file_inode_operations;
207         inode->i_fop = &sysv_file_operations;
208         inode->i_mapping->a_ops = &sysv_aops;
209         inode->i_mode = mode;
210         mark_inode_dirty(inode);
211         error = sysv_add_entry(dir, dentry->d_name.name,
212                                dentry->d_name.len, &bh, &de);
213         if (error) {
214                 inode->i_nlink--;
215                 mark_inode_dirty(inode);
216                 iput(inode);
217                 return error;
218         }
219         de->inode = inode->i_ino;
220         mark_buffer_dirty(bh);
221         brelse(bh);
222         d_instantiate(dentry, inode);
223         return 0;
224 }
225 
226 static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
227 {
228         int error;
229         struct inode * inode;
230         struct buffer_head * bh;
231         struct sysv_dir_entry * de;
232 
233         bh = sysv_find_entry(dir, dentry->d_name.name,
234                              dentry->d_name.len, &de);
235         if (bh) {
236                 brelse(bh);
237                 return -EEXIST;
238         }
239         inode = sysv_new_inode(dir);
240         if (!inode)
241                 return -ENOSPC;
242         inode->i_uid = current->fsuid;
243         init_special_inode(inode, mode, rdev);
244         mark_inode_dirty(inode);
245         error = sysv_add_entry(dir, dentry->d_name.name, 
246                                dentry->d_name.len, &bh, &de);
247         if (error) {
248                 inode->i_nlink--;
249                 mark_inode_dirty(inode);
250                 iput(inode);
251                 return error;
252         }
253         de->inode = inode->i_ino;
254         mark_buffer_dirty(bh);
255         brelse(bh);
256         d_instantiate(dentry, inode);
257         return 0;
258 }
259 
260 static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
261 {
262         int error;
263         struct inode * inode;
264         struct buffer_head * bh, *dir_block;
265         struct sysv_dir_entry * de;
266 
267         bh = sysv_find_entry(dir, dentry->d_name.name,
268                               dentry->d_name.len, &de);
269         if (bh) {
270                 brelse(bh);
271                 return -EEXIST;
272         }
273         if (dir->i_nlink >= dir->i_sb->sv_link_max) 
274                 return -EMLINK;
275         inode = sysv_new_inode(dir);
276         if (!inode)
277                 return -ENOSPC;
278         inode->i_op = &sysv_dir_inode_operations;
279         inode->i_fop = &sysv_dir_operations;
280         inode->i_size = 2 * SYSV_DIRSIZE;
281         dir_block = sysv_file_bread(inode,0,1);
282         if (!dir_block) {
283                 inode->i_nlink--;
284                 mark_inode_dirty(inode);
285                 iput(inode);
286                 return -ENOSPC;
287         }
288         de = (struct sysv_dir_entry *) (dir_block->b_data + 0*SYSV_DIRSIZE);
289         de->inode = inode->i_ino;
290         strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */
291         de = (struct sysv_dir_entry *) (dir_block->b_data + 1*SYSV_DIRSIZE);
292         de->inode = dir->i_ino;
293         strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */
294         inode->i_nlink = 2;
295         mark_buffer_dirty(dir_block);
296         brelse(dir_block);
297         inode->i_mode = S_IFDIR | mode;
298         if (dir->i_mode & S_ISGID)
299                 inode->i_mode |= S_ISGID;
300         mark_inode_dirty(inode);
301         error = sysv_add_entry(dir, dentry->d_name.name,
302                                dentry->d_name.len, &bh, &de);
303         if (error) {
304                 inode->i_nlink=0;
305                 iput(inode);
306                 return error;
307         }
308         de->inode = inode->i_ino;
309         mark_buffer_dirty(bh);
310         dir->i_nlink++;
311         mark_inode_dirty(dir);
312         brelse(bh);
313         d_instantiate(dentry, inode);
314         return 0;
315 }
316 
317 /*
318  * routine to check that the specified directory is empty (for rmdir)
319  */
320 static int empty_dir(struct inode * inode)
321 {
322         struct super_block * sb;
323         unsigned long pos, block, offset; /* pos = block * block_size + offset */
324         struct buffer_head * bh;
325         struct sysv_dir_entry * de;
326 
327         block = 0;
328         bh = NULL;
329         pos = offset = 2*SYSV_DIRSIZE;
330         if ((unsigned long)(inode->i_size) % SYSV_DIRSIZE)
331                 goto bad_dir;
332         if (inode->i_size < pos)
333                 goto bad_dir;
334         bh = sysv_file_bread(inode, 0, 0);
335         if (!bh)
336                 goto bad_dir;
337         de = (struct sysv_dir_entry *) (bh->b_data + 0*SYSV_DIRSIZE);
338         if (!de->inode || strcmp(de->name,"."))
339                 goto bad_dir;
340         de = (struct sysv_dir_entry *) (bh->b_data + 1*SYSV_DIRSIZE);
341         if (!de->inode || strcmp(de->name,".."))
342                 goto bad_dir;
343         sb = inode->i_sb;
344         while (pos < inode->i_size) {
345                 if (!bh) {
346                         bh = sysv_file_bread(inode, block, 0);
347                         if (!bh) {
348                                 /* offset = 0; */ block++;
349                                 pos += sb->sv_block_size;
350                                 continue;
351                         }
352                 }
353                 de = (struct sysv_dir_entry *) (bh->b_data + offset);
354                 pos += SYSV_DIRSIZE;
355                 offset += SYSV_DIRSIZE;
356                 if (de->inode) {
357                         brelse(bh);
358                         return 0;
359                 }
360                 if (offset < sb->sv_block_size)
361                         continue;
362                 brelse(bh);
363                 bh = NULL;
364                 offset = 0; block++;
365         }
366         brelse(bh);
367         return 1;
368 bad_dir:
369         brelse(bh);
370         printk("Bad directory on device %s\n",
371                kdevname(inode->i_dev));
372         return 1;
373 }
374 
375 static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
376 {
377         int retval;
378         struct inode * inode;
379         struct buffer_head * bh;
380         struct sysv_dir_entry * de;
381 
382         inode = dentry->d_inode;
383         bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
384         retval = -ENOENT;
385         if (!bh || de->inode != inode->i_ino)
386                 goto end_rmdir;
387 
388         if (!empty_dir(inode)) {
389                 retval = -ENOTEMPTY;
390                 goto end_rmdir;
391         }
392         if (inode->i_nlink != 2)
393                 printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink);
394         de->inode = 0;
395         mark_buffer_dirty(bh);
396         inode->i_nlink=0;
397         dir->i_nlink--;
398         inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
399         mark_inode_dirty(inode);
400         mark_inode_dirty(dir);
401         retval = 0;
402 end_rmdir:
403         brelse(bh);
404         return retval;
405 }
406 
407 static int sysv_unlink(struct inode * dir, struct dentry * dentry)
408 {
409         int retval;
410         struct inode * inode;
411         struct buffer_head * bh;
412         struct sysv_dir_entry * de;
413 
414         retval = -ENOENT;
415         inode = dentry->d_inode;
416         bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
417         if (!bh || de->inode != inode->i_ino)
418                 goto end_unlink;
419         if (!inode->i_nlink) {
420                 printk("Deleting nonexistent file (%s:%lu), %d\n",
421                         kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
422                 inode->i_nlink=1;
423         }
424         de->inode = 0;
425         mark_buffer_dirty(bh);
426         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
427         mark_inode_dirty(dir);
428         inode->i_nlink--;
429         inode->i_ctime = dir->i_ctime;
430         mark_inode_dirty(inode);
431         retval = 0;
432 end_unlink:
433         brelse(bh);
434         return retval;
435 }
436 
437 static int sysv_symlink(struct inode * dir, struct dentry * dentry, 
438                  const char * symname)
439 {
440         struct inode * inode;
441         struct sysv_dir_entry * de;
442         struct buffer_head * bh;
443         int err;
444         int l;
445 
446         err = -ENAMETOOLONG;
447         l = strlen(symname)+1;
448         if (l > dir->i_sb->sv_block_size_1)
449                 goto out;
450         err = -ENOSPC;
451         if (!(inode = sysv_new_inode(dir)))
452                 goto out;
453 
454         inode->i_mode = S_IFLNK | 0777;
455         inode->i_op = &sysv_symlink_inode_operations;
456         inode->i_mapping->a_ops = &sysv_aops;
457         err = block_symlink(inode, symname, l);
458         if (err)
459                 goto out_no_entry;
460         mark_inode_dirty(inode);
461         err = sysv_add_entry(dir, dentry->d_name.name,
462                            dentry->d_name.len, &bh, &de);
463         if (err)
464                 goto out_no_entry;
465         de->inode = inode->i_ino;
466         mark_buffer_dirty(bh);
467         brelse(bh);
468         d_instantiate(dentry, inode);
469 out:
470         return err;
471 out_no_entry:
472         inode->i_nlink--;
473         mark_inode_dirty(inode);
474         iput(inode);
475         goto out;
476 }
477 
478 static int sysv_link(struct dentry * old_dentry, struct inode * dir, 
479               struct dentry * dentry)
480 {
481         struct inode *oldinode = old_dentry->d_inode;
482         int error;
483         struct sysv_dir_entry * de;
484         struct buffer_head * bh;
485 
486         if (S_ISDIR(oldinode->i_mode)) {
487                 return -EPERM;
488         }
489         if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) {
490                 return -EMLINK;
491         }
492         bh = sysv_find_entry(dir, dentry->d_name.name,
493                              dentry->d_name.len, &de);
494         if (bh) {
495                 brelse(bh);
496                 return -EEXIST;
497         }
498         error = sysv_add_entry(dir, dentry->d_name.name,
499                                dentry->d_name.len, &bh, &de);
500         if (error) {
501                 brelse(bh);
502                 return error;
503         }
504         de->inode = oldinode->i_ino;
505         mark_buffer_dirty(bh);
506         brelse(bh);
507         oldinode->i_nlink++;
508         oldinode->i_ctime = CURRENT_TIME;
509         mark_inode_dirty(oldinode);
510         atomic_inc(&oldinode->i_count);
511         d_instantiate(dentry, oldinode);
512         return 0;
513 }
514 
515 #define PARENT_INO(buffer) \
516 (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode)
517 
518 /*
519  * Anybody can rename anything with this: the permission checks are left to the
520  * higher-level routines.
521  */
522 static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
523                   struct inode * new_dir, struct dentry * new_dentry)
524 {
525         struct inode * old_inode, * new_inode;
526         struct buffer_head * old_bh, * new_bh, * dir_bh;
527         struct sysv_dir_entry * old_de, * new_de;
528         int retval;
529 
530         old_inode = old_dentry->d_inode;
531         new_inode = new_dentry->d_inode;
532         new_bh = dir_bh = NULL;
533         old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name,
534                                 old_dentry->d_name.len, &old_de);
535         retval = -ENOENT;
536         if (!old_bh || old_de->inode != old_inode->i_ino)
537                 goto end_rename;
538         retval = -EPERM;
539         new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
540                                 new_dentry->d_name.len, &new_de);
541         if (new_bh) {
542                 if (!new_inode) {
543                         brelse(new_bh);
544                         new_bh = NULL;
545                 }
546         }
547         if (S_ISDIR(old_inode->i_mode)) {
548                 if (new_inode) {
549                         retval = -ENOTEMPTY;
550                         if (!empty_dir(new_inode))
551                                 goto end_rename;
552                 }
553                 retval = -EIO;
554                 dir_bh = sysv_file_bread(old_inode, 0, 0);
555                 if (!dir_bh)
556                         goto end_rename;
557                 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
558                         goto end_rename;
559                 retval = -EMLINK;
560                 if (!new_inode && new_dir != old_dir &&
561                                 new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
562                         goto end_rename;
563         }
564         if (!new_bh) {
565                 retval = sysv_add_entry(new_dir, new_dentry->d_name.name,
566                                         new_dentry->d_name.len, &new_bh, &new_de);
567                 if (retval)
568                         goto end_rename;
569         }
570         new_de->inode = old_inode->i_ino;
571         old_de->inode = 0;
572         old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
573         mark_inode_dirty(old_dir);
574         new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
575         mark_inode_dirty(new_dir);
576         if (new_inode) {
577                 new_inode->i_nlink--;
578                 new_inode->i_ctime = CURRENT_TIME;
579                 mark_inode_dirty(new_inode);
580         }
581         mark_buffer_dirty(old_bh);
582         mark_buffer_dirty(new_bh);
583         if (dir_bh) {
584                 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
585                 mark_buffer_dirty(dir_bh);
586                 old_dir->i_nlink--;
587                 mark_inode_dirty(old_dir);
588                 if (new_inode) {
589                         new_inode->i_nlink--;
590                         mark_inode_dirty(new_inode);
591                 } else {
592                         new_dir->i_nlink++;
593                         mark_inode_dirty(new_dir);
594                 }
595         }
596         retval = 0;
597 end_rename:
598         brelse(dir_bh);
599         brelse(old_bh);
600         brelse(new_bh);
601         return retval;
602 }
603 
604 /*
605  * directories can handle most operations...
606  */
607 struct inode_operations sysv_dir_inode_operations = {
608         create:         sysv_create,
609         lookup:         sysv_lookup,
610         link:           sysv_link,
611         unlink:         sysv_unlink,
612         symlink:        sysv_symlink,
613         mkdir:          sysv_mkdir,
614         rmdir:          sysv_rmdir,
615         mknod:          sysv_mknod,
616         rename:         sysv_rename,
617         setattr:        sysv_notify_change,
618 };
619 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.