source: rtems/cpukit/libfs/src/imfs/imfs_directory.c @ 316507ab

4.115
Last change on this file since 316507ab was 316507ab, checked in by Sebastian Huber <sebastian.huber@…>, on 02/21/12 at 16:21:05

IMFS: Lock the file system during directory reads

Other threads may add or remove directory entries during a read of the
directory. Use the file system instance lock for protection.

  • Property mode set to 100644
File size: 5.5 KB
Line 
1/*
2 *  IMFS Directory Access Routines
3 *
4 *  COPYRIGHT (c) 1989-1999.
5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#if HAVE_CONFIG_H
15  #include "config.h"
16#endif
17
18#include "imfs.h"
19
20#include <string.h>
21#include <dirent.h>
22
23/*
24 *  imfs_dir_open
25 *
26 *  This rountine will verify that the node being opened as a directory is
27 *  in fact a directory node. If it is then the offset into the directory
28 *  will be set to 0 to position to the first directory entry.
29 */
30
31int imfs_dir_open(
32  rtems_libio_t  *iop,
33  const char *pathname,
34  int oflag,
35  mode_t mode
36)
37{
38  IMFS_jnode_t      *the_jnode;
39
40  /* Is the node a directory ? */
41  the_jnode = (IMFS_jnode_t *) iop->pathinfo.node_access;
42
43  if ( the_jnode->type != IMFS_DIRECTORY )
44     return -1;      /* It wasn't a directory --> return error */
45
46  iop->offset = 0;
47  return 0;
48}
49
50/*
51 *  imfs_dir_read
52 *
53 *  This routine will read the next directory entry based on the directory
54 *  offset. The offset should be equal to -n- time the size of an individual
55 *  dirent structure. If n is not an integer multiple of the sizeof a
56 *  dirent structure, an integer division will be performed to determine
57 *  directory entry that will be returned in the buffer. Count should reflect
58 *  -m- times the sizeof dirent bytes to be placed in the buffer.
59 *  If there are not -m- dirent elements from the current directory position
60 *  to the end of the exisiting file, the remaining entries will be placed in
61 *  the buffer and the returned value will be equal to -m actual- times the
62 *  size of a directory entry.
63 */
64
65ssize_t imfs_dir_read(
66  rtems_libio_t  *iop,
67  void           *buffer,
68  size_t          count
69)
70{
71  /*
72   *  Read up to element  iop->offset in the directory chain of the
73   *  imfs_jnode_t struct for this file descriptor.
74   */
75   rtems_chain_node    *the_node;
76   rtems_chain_control *the_chain;
77   IMFS_jnode_t        *the_jnode;
78   int                  bytes_transferred;
79   int                  current_entry;
80   int                  first_entry;
81   int                  last_entry;
82   struct dirent        tmp_dirent;
83
84   rtems_filesystem_instance_lock( &iop->pathinfo );
85
86   the_jnode = (IMFS_jnode_t *)iop->pathinfo.node_access;
87   the_chain = &the_jnode->info.directory.Entries;
88
89   /* Move to the first of the desired directory entries */
90
91   bytes_transferred = 0;
92   first_entry = iop->offset;
93   /* protect against using sizes that are not exact multiples of the */
94   /* -dirent- size. These could result in unexpected results          */
95   last_entry = first_entry
96     + (count / sizeof( struct dirent )) * sizeof( struct dirent );
97
98   /* The directory was not empty so try to move to the desired entry in chain*/
99   for (
100      current_entry = 0,
101        the_node = rtems_chain_first( the_chain );
102      current_entry < last_entry
103        && !rtems_chain_is_tail( the_chain, the_node );
104      current_entry +=  sizeof( struct dirent ),
105        the_node = rtems_chain_next( the_node )
106   ) {
107      if( current_entry >= first_entry ) {
108         /* Move the entry to the return buffer */
109         tmp_dirent.d_off = current_entry;
110         tmp_dirent.d_reclen = sizeof( struct dirent );
111         the_jnode = (IMFS_jnode_t *) the_node;
112         tmp_dirent.d_ino = the_jnode->st_ino;
113         tmp_dirent.d_namlen = strlen( the_jnode->name );
114         strcpy( tmp_dirent.d_name, the_jnode->name );
115         memcpy(
116            buffer + bytes_transferred,
117            (void *)&tmp_dirent,
118            sizeof( struct dirent )
119         );
120         iop->offset += sizeof( struct dirent );
121         bytes_transferred += sizeof( struct dirent );
122      }
123   }
124
125   rtems_filesystem_instance_unlock( &iop->pathinfo );
126
127   return bytes_transferred;
128}
129
130
131
132/*
133 *  imfs_dir_close
134 *
135 *  This routine will be called by the generic close routine to cleanup any
136 *  resources that have been allocated for the management of the file
137 */
138
139int imfs_dir_close(
140  rtems_libio_t  *iop
141)
142{
143  /*
144   *  The generic close routine handles the deallocation of the file control
145   *  and associated memory. At present the imfs_dir_close simply
146   *  returns a successful completion status.
147   */
148
149  return 0;
150}
151
152
153
154/*
155 *  imfs_dir_lseek
156 *
157 *  This routine will behave in one of three ways based on the state of
158 *  argument whence. Based on the state of its value the offset argument will
159 *  be interpreted using one of the following methods:
160 *
161 *     SEEK_SET - offset is the absolute byte offset from the start of the
162 *                logical start of the dirent sequence that represents the
163 *                directory
164 *     SEEK_CUR - offset is used as the relative byte offset from the current
165 *                directory position index held in the iop structure
166 *     SEEK_END - N/A --> This will cause an EINVAL to be returned.
167 */
168
169off_t imfs_dir_lseek(
170  rtems_libio_t  *iop,
171  off_t           offset,
172  int             whence
173)
174{
175  switch( whence ) {
176     case SEEK_SET:   /* absolute move from the start of the file */
177     case SEEK_CUR:   /* relative move */
178        iop->offset = (iop->offset/sizeof(struct dirent)) *
179              sizeof(struct dirent);
180        break;
181
182     case SEEK_END:   /* Movement past the end of the directory via lseek */
183                      /* is not a permitted operation                     */
184      default:
185        rtems_set_errno_and_return_minus_one( EINVAL );
186        break;
187  }
188
189  return 0;
190}
Note: See TracBrowser for help on using the repository browser.