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

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

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

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

~ [ 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.