dir.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  3.  */
  4. #include <linux/config.h>
  5. #include <linux/string.h>
  6. #include <linux/errno.h>
  7. #include <linux/fs.h>
  8. #include <linux/reiserfs_fs.h>
  9. #include <linux/stat.h>
  10. #include <linux/smp_lock.h>
  11. #include <asm/uaccess.h>
  12. extern struct key  MIN_KEY;
  13. static int reiserfs_readdir (struct file *, void *, filldir_t);
  14. int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) ;
  15. struct file_operations reiserfs_dir_operations = {
  16.     read: generic_read_dir,
  17.     readdir: reiserfs_readdir,
  18.     fsync: reiserfs_dir_fsync,
  19.     ioctl: reiserfs_ioctl,
  20. };
  21. int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
  22.   lock_kernel();
  23.   reiserfs_commit_for_inode(dentry->d_inode) ;
  24.   unlock_kernel() ;
  25.   return 0 ;
  26. }
  27. #define store_ih(where,what) copy_item_head (where, what)
  28. //
  29. static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldir)
  30. {
  31.     struct inode *inode = filp->f_dentry->d_inode;
  32.     struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
  33.     INITIALIZE_PATH (path_to_entry);
  34.     struct buffer_head * bh;
  35.     int item_num, entry_num;
  36.     const struct key * rkey;
  37.     struct item_head * ih, tmp_ih;
  38.     int search_res;
  39.     char * local_buf;
  40.     loff_t next_pos;
  41.     char small_buf[32] ; /* avoid kmalloc if we can */
  42.     struct reiserfs_dir_entry de;
  43.     reiserfs_check_lock_depth("readdir") ;
  44.     /* form key for search the next directory entry using f_pos field of
  45.        file structure */
  46.     make_cpu_key (&pos_key, inode, (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET,
  47.   TYPE_DIRENTRY, 3);
  48.     next_pos = cpu_key_k_offset (&pos_key);
  49.     /*  reiserfs_warning ("reiserfs_readdir 1: f_pos = %Ldn", filp->f_pos);*/
  50.     while (1) {
  51.     research:
  52. /* search the directory item, containing entry with specified key */
  53. search_res = search_by_entry_key (inode->i_sb, &pos_key, &path_to_entry, &de);
  54. if (search_res == IO_ERROR) {
  55.     // FIXME: we could just skip part of directory which could
  56.     // not be read
  57.     return -EIO;
  58. }
  59. entry_num = de.de_entry_num;
  60. bh = de.de_bh;
  61. item_num = de.de_item_num;
  62. ih = de.de_ih;
  63. store_ih (&tmp_ih, ih);
  64. /* we must have found item, that is item of this directory, */
  65. RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
  66. "vs-9000: found item %h does not match to dir we readdir %K",
  67. ih, &pos_key);
  68. RFALSE( item_num > B_NR_ITEMS (bh) - 1,
  69. "vs-9005 item_num == %d, item amount == %d", 
  70. item_num, B_NR_ITEMS (bh));
  71.       
  72. /* and entry must be not more than number of entries in the item */
  73. RFALSE( I_ENTRY_COUNT (ih) < entry_num,
  74. "vs-9010: entry number is too big %d (%d)", 
  75. entry_num, I_ENTRY_COUNT (ih));
  76. if (search_res == POSITION_FOUND || entry_num < I_ENTRY_COUNT (ih)) {
  77.     /* go through all entries in the directory item beginning from the entry, that has been found */
  78.     struct reiserfs_de_head * deh = B_I_DEH (bh, ih) + entry_num;
  79.     for (; entry_num < I_ENTRY_COUNT (ih); entry_num ++, deh ++) {
  80. int d_reclen;
  81. char * d_name;
  82. off_t d_off;
  83. ino_t d_ino;
  84. if (!de_visible (deh))
  85.     /* it is hidden entry */
  86.     continue;
  87. d_reclen = entry_length (bh, ih, entry_num);
  88. d_name = B_I_DEH_ENTRY_FILE_NAME (bh, ih, deh);
  89. if (!d_name[d_reclen - 1])
  90.     d_reclen = strlen (d_name);
  91. if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)){
  92.     /* too big to send back to VFS */
  93.     continue ;
  94. }
  95. d_off = deh_offset (deh);
  96. filp->f_pos = d_off ;
  97. d_ino = deh_objectid (deh);
  98. if (d_reclen <= 32) {
  99.   local_buf = small_buf ;
  100. } else {
  101.     local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
  102.     if (!local_buf) {
  103. pathrelse (&path_to_entry);
  104. return -ENOMEM ;
  105.     }
  106.     if (item_moved (&tmp_ih, &path_to_entry)) {
  107. reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
  108. goto research;
  109.     }
  110. }
  111. // Note, that we copy name to user space via temporary
  112. // buffer (local_buf) because filldir will block if
  113. // user space buffer is swapped out. At that time
  114. // entry can move to somewhere else
  115. memcpy (local_buf, d_name, d_reclen);
  116. if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, 
  117.              DT_UNKNOWN) < 0) {
  118.     if (local_buf != small_buf) {
  119. reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
  120.     }
  121.     goto end;
  122. }
  123. if (local_buf != small_buf) {
  124.     reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
  125. }
  126. // next entry should be looked for with such offset
  127. next_pos = deh_offset (deh) + 1;
  128. if (item_moved (&tmp_ih, &path_to_entry)) {
  129.     goto research;
  130. }
  131.     } /* for */
  132. }
  133. if (item_num != B_NR_ITEMS (bh) - 1)
  134.     // end of directory has been reached
  135.     goto end;
  136. /* item we went through is last item of node. Using right
  137.    delimiting key check is it directory end */
  138. rkey = get_rkey (&path_to_entry, inode->i_sb);
  139. if (! comp_le_keys (rkey, &MIN_KEY)) {
  140.     /* set pos_key to key, that is the smallest and greater
  141.        that key of the last entry in the item */
  142.     set_cpu_key_k_offset (&pos_key, next_pos);
  143.     continue;
  144. }
  145. if ( COMP_SHORT_KEYS (rkey, &pos_key)) {
  146.     // end of directory has been reached
  147.     goto end;
  148. }
  149. /* directory continues in the right neighboring block */
  150. set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey));
  151.     } /* while */
  152.  end:
  153.     filp->f_pos = next_pos;
  154.     pathrelse (&path_to_entry);
  155.     reiserfs_check_path(&path_to_entry) ;
  156.     UPDATE_ATIME(inode) ;
  157.     return 0;
  158. }
  159. /* compose directory item containing "." and ".." entries (entries are
  160.    not aligned to 4 byte boundary) */
  161. /* the last four params are LE */
  162. void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
  163.      __u32 par_dirid, __u32 par_objid)
  164. {
  165.     struct reiserfs_de_head * deh;
  166.     memset (body, 0, EMPTY_DIR_SIZE_V1);
  167.     deh = (struct reiserfs_de_head *)body;
  168.     
  169.     /* direntry header of "." */
  170.     put_deh_offset( &(deh[0]), DOT_OFFSET );
  171.     /* these two are from make_le_item_head, and are are LE */
  172.     deh[0].deh_dir_id = dirid;
  173.     deh[0].deh_objectid = objid;
  174.     deh[0].deh_state = 0; /* Endian safe if 0 */
  175.     put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." ));
  176.     mark_de_visible(&(deh[0]));
  177.   
  178.     /* direntry header of ".." */
  179.     put_deh_offset( &(deh[1]), DOT_DOT_OFFSET);
  180.     /* key of ".." for the root directory */
  181.     /* these two are from the inode, and are are LE */
  182.     deh[1].deh_dir_id = par_dirid;
  183.     deh[1].deh_objectid = par_objid;
  184.     deh[1].deh_state = 0; /* Endian safe if 0 */
  185.     put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) );
  186.     mark_de_visible(&(deh[1]));
  187.     /* copy ".." and "." */
  188.     memcpy (body + deh_location( &(deh[0]) ), ".", 1);
  189.     memcpy (body + deh_location( &(deh[1]) ), "..", 2);
  190. }
  191. /* compose directory item containing "." and ".." entries */
  192. void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
  193.   __u32 par_dirid, __u32 par_objid)
  194. {
  195.     struct reiserfs_de_head * deh;
  196.     memset (body, 0, EMPTY_DIR_SIZE);
  197.     deh = (struct reiserfs_de_head *)body;
  198.     
  199.     /* direntry header of "." */
  200.     put_deh_offset( &(deh[0]), DOT_OFFSET );
  201.     /* these two are from make_le_item_head, and are are LE */
  202.     deh[0].deh_dir_id = dirid;
  203.     deh[0].deh_objectid = objid;
  204.     deh[0].deh_state = 0; /* Endian safe if 0 */
  205.     put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) );
  206.     mark_de_visible(&(deh[0]));
  207.   
  208.     /* direntry header of ".." */
  209.     put_deh_offset( &(deh[1]), DOT_DOT_OFFSET );
  210.     /* key of ".." for the root directory */
  211.     /* these two are from the inode, and are are LE */
  212.     deh[1].deh_dir_id = par_dirid;
  213.     deh[1].deh_objectid = par_objid;
  214.     deh[1].deh_state = 0; /* Endian safe if 0 */
  215.     put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) );
  216.     mark_de_visible(&(deh[1]));
  217.     /* copy ".." and "." */
  218.     memcpy (body + deh_location( &(deh[0]) ), ".", 1);
  219.     memcpy (body + deh_location( &(deh[1]) ), "..", 2);
  220. }