dir.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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