source: rtems/cpukit/libfs/src/rfs/rtems-rfs-dir.c @ 355b0544

4.104.11
Last change on this file since 355b0544 was 355b0544, checked in by Chris Johns <chrisj@…>, on Mar 27, 2010 at 4:04:40 AM

2010-03-27 Chris Johns <chrisj@…>

libfs/src/nfsclient/src/cexphelp.c,
libfs/src/nfsclient/src/dirutils.c,
libfs/src/nfsclient/src/nfs.modini.c,
libfs/src/nfsclient/src/nfsTest.c,
libfs/src/nfsclient/src/rpcio.c,
libfs/src/nfsclient/src/rpcio.modini.c,
libfs/src/nfsclient/src/sock_mbuf.c,
libfs/src/nfsclient/src/xdr_mbuf.c,
libfs/src/rfs/rtems-rfs-bitmaps-ut.c,
libfs/src/rfs/rtems-rfs-bitmaps.c,
libfs/src/rfs/rtems-rfs-block.c,
libfs/src/rfs/rtems-rfs-buffer-bdbuf.c,
libfs/src/rfs/rtems-rfs-buffer-devio.c,
libfs/src/rfs/rtems-rfs-buffer.c,
libfs/src/rfs/rtems-rfs-dir-hash.c, libfs/src/rfs/rtems-rfs-dir.c,
libfs/src/rfs/rtems-rfs-file-system.c,
libfs/src/rfs/rtems-rfs-file.c, libfs/src/rfs/rtems-rfs-format.c,
libfs/src/rfs/rtems-rfs-group.c, libfs/src/rfs/rtems-rfs-inode.c,
libfs/src/rfs/rtems-rfs-link.c, libfs/src/rfs/rtems-rfs-mutex.c,
libfs/src/rfs/rtems-rfs-rtems-dev.c,
libfs/src/rfs/rtems-rfs-rtems-dir.c,
libfs/src/rfs/rtems-rfs-rtems-file.c,
libfs/src/rfs/rtems-rfs-rtems-utils.c,
libfs/src/rfs/rtems-rfs-rtems.c, libfs/src/rfs/rtems-rfs-shell.c,
libfs/src/rfs/rtems-rfs-trace.c: Add HAVE_CONFIG_H support to let
files receive configure defines.

  • Property mode set to 100644
File size: 21.1 KB
Line 
1/*
2 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.com/license/LICENSE.
7 *
8 *  $Id$
9 */
10/**
11 * @file
12 *
13 * @ingroup rtems-rfs
14 *
15 * RTEMS File Systems Directory Routines.
16 *
17 * These functions manage blocks in the directory format. A directory entry is
18 * a variable length record in the block. The entry consists of a length, hash
19 * and the string. The length allows the next entry to be located and the hash
20 * allows a simple check to be performed wihtout a string compare. Directory
21 * entries do not span a block and removal of an entry results in the space in
22 * the block being compacted and the spare area being initialised to ones.
23 *
24 * The maximum length can be 1 or 2 bytes depending on the value in the
25 * superblock.
26 */
27
28#if HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <rtems/rfs/rtems-rfs-block.h>
33#include <rtems/rfs/rtems-rfs-buffer.h>
34#include <rtems/rfs/rtems-rfs-file-system.h>
35#include <rtems/rfs/rtems-rfs-trace.h>
36#include <rtems/rfs/rtems-rfs-dir.h>
37#include <rtems/rfs/rtems-rfs-dir-hash.h>
38
39/**
40 * Validate the directory entry data.
41 */
42#define rtems_rfs_dir_entry_valid(_f, _l, _i) \
43  (((_l) <= RTEMS_RFS_DIR_ENTRY_SIZE) || ((_l) >= rtems_rfs_fs_max_name (_f)) \
44   || (_i < RTEMS_RFS_ROOT_INO) || (_i > rtems_rfs_fs_inodes (_f)))
45
46int
47rtems_rfs_dir_lookup_ino (rtems_rfs_file_system*  fs,
48                          rtems_rfs_inode_handle* inode,
49                          const char*             name,
50                          int                     length,
51                          rtems_rfs_ino*          ino,
52                          uint32_t*               offset)
53{
54  rtems_rfs_block_map     map;
55  rtems_rfs_buffer_handle entries;
56  int                     rc;
57
58  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
59  {
60    int c;
61    printf ("rtems-rfs: dir-lookup-ino: lookup ino: root=%ld, path=",
62            inode->ino);
63    for (c = 0; c < length; c++)
64      printf ("%c", name[c]);
65    printf (", len=%d\n", length);
66  }
67
68  *ino = RTEMS_RFS_EMPTY_INO;
69  *offset = 0;
70 
71  rc = rtems_rfs_block_map_open (fs, inode, &map);
72  if (rc > 0)
73  {
74    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
75      printf ("rtems-rfs: dir-lookup-ino: map open failed for ino %lu: %d: %s",
76              rtems_rfs_inode_ino (inode), rc, strerror (rc));
77    return rc;
78  }
79 
80  rc = rtems_rfs_buffer_handle_open (fs, &entries);
81  if (rc > 0)
82  {
83    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
84      printf ("rtems-rfs: dir-lookup-ino: handle open failed for ino %lu: %d: %s",
85              rtems_rfs_inode_ino (inode), rc, strerror (rc));
86    rtems_rfs_block_map_close (fs, &map);
87    return rc;
88  }
89  else
90  {
91    rtems_rfs_block_no block;
92    uint32_t           hash;
93
94    /*
95     * Calculate the hash of the look up string.
96     */
97    hash = rtems_rfs_dir_hash (name, length);
98 
99    /*
100     * Locate the first block. The map points to the start after open so just
101     * seek 0. If an error the block will be 0.
102     */
103    rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
104    if (rc > 0)
105    {
106      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
107        printf ("rtems-rfs: dir-lookup-ino: block map find failed: %d: %s\n",
108                rc, strerror (rc));
109      if (rc == ENXIO)
110        rc = ENOENT;
111      rtems_rfs_buffer_handle_close (fs, &entries);
112      rtems_rfs_block_map_close (fs, &map);
113      return rc;
114    }
115       
116    while ((rc == 0) && block)
117    {
118      uint8_t* entry;
119     
120      rc = rtems_rfs_buffer_handle_request (fs, &entries, block, true); 
121      if (rc > 0)
122      {
123        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
124          printf ("rtems-rfs: dir-lookup-ino: block read, ino=%lu block=%ld: %d: %s\n",
125                  rtems_rfs_inode_ino (inode), block, rc, strerror (rc));
126        break;
127      }
128
129      /*
130       * Search the block to see if the name matches. A hash of 0xffff or 0x0
131       * means the entry is empty.
132       */
133
134      entry = rtems_rfs_buffer_data (&entries);
135     
136      map.bpos.boff = 0;
137
138      while (map.bpos.boff < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
139      {
140        uint32_t ehash;
141        int      elength;
142     
143        ehash  = rtems_rfs_dir_entry_hash (entry);
144        elength = rtems_rfs_dir_entry_length (entry);
145        *ino = rtems_rfs_dir_entry_ino (entry);
146
147        if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
148          break;
149       
150        if (rtems_rfs_dir_entry_valid (fs, elength, *ino))
151        {
152          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
153            printf ("rtems-rfs: dir-lookup-ino: " \
154                    "bad length or ino for ino %lu: %u/%ld @ %04lx\n",
155                    rtems_rfs_inode_ino (inode), elength, *ino, map.bpos.boff);
156          rc = EIO;
157          break;
158        }
159         
160        if (ehash == hash)
161        {
162          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_CHECK))
163            printf ("rtems-rfs: dir-lookup-ino: " \
164                    "checking entry for ino %ld: off=%04lx length:%d ino:%d\n",
165                    rtems_rfs_inode_ino (inode), map.bpos.boff,
166                    elength, rtems_rfs_dir_entry_ino (entry));
167
168          if (memcmp (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length) == 0)
169          {
170            *offset = rtems_rfs_block_map_pos (fs, &map);
171           
172            if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_FOUND))
173              printf ("rtems-rfs: dir-lookup-ino: " \
174                      "entry found in ino %lu, ino=%lu offset=%lu\n",
175                      rtems_rfs_inode_ino (inode), *ino, *offset);
176
177            rtems_rfs_buffer_handle_close (fs, &entries);
178            rtems_rfs_block_map_close (fs, &map);
179            return 0;
180          }
181        }
182
183        map.bpos.boff += elength;
184        entry += elength;
185      }
186
187      if (rc == 0)
188      {
189        rc = rtems_rfs_block_map_next_block (fs, &map, &block);
190        if ((rc > 0) && (rc != ENXIO))
191        {
192          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
193            printf ("rtems-rfs: dir-lookup-ino: " \
194                    "block map next block failed in ino %lu: %d: %s\n",
195                    rtems_rfs_inode_ino (inode), rc, strerror (rc));
196        }
197        if (rc == ENXIO)
198          rc = ENOENT;
199      }
200    }
201
202    if ((rc == 0) && (block == 0))
203    {
204      rc = EIO;
205      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
206        printf ("rtems-rfs: dir-lookup-ino: block is 0 in ino %lu: %d: %s\n",
207                rtems_rfs_inode_ino (inode), rc, strerror (rc));
208    }
209  }
210 
211  rtems_rfs_buffer_handle_close (fs, &entries);
212  rtems_rfs_block_map_close (fs, &map);
213  return rc;
214}
215
216int
217rtems_rfs_dir_add_entry (rtems_rfs_file_system*  fs,
218                         rtems_rfs_inode_handle* dir,
219                         const char*             name,
220                         size_t                  length,
221                         rtems_rfs_ino           ino)
222{
223  rtems_rfs_block_map     map;
224  rtems_rfs_block_pos     bpos;
225  rtems_rfs_buffer_handle buffer;
226  int                     rc;
227
228  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
229  {
230    int c;
231    printf ("rtems-rfs: dir-add-entry: dir=%ld, name=",
232            rtems_rfs_inode_ino (dir));
233    for (c = 0; c < length; c++)
234      printf ("%c", name[c]);
235    printf (", len=%zd\n", length);
236  }
237       
238  rc = rtems_rfs_block_map_open (fs, dir, &map);
239  if (rc > 0)
240    return rc;
241
242  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
243  if (rc > 0)
244  {
245    rtems_rfs_block_map_close (fs, &map);
246    return rc;
247  }
248 
249  /*
250   * Search the map from the beginning to find any empty space.
251   */
252  rtems_rfs_block_set_bpos_zero (&bpos);
253 
254  while (true)
255  {
256    rtems_rfs_block_no block;
257    uint8_t*           entry;
258    int                offset;
259    bool               read = true;
260   
261    /*
262     * Locate the first block. If an error the block will be 0. If the map is
263     * empty which happens when creating a directory and adding the first entry
264     * the seek will return ENXIO. In this case we need to grow the directory.
265     */
266    rc = rtems_rfs_block_map_find (fs, &map, &bpos, &block);
267    if (rc > 0)
268    {
269      if (rc != ENXIO)
270      {
271        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
272          printf ("rtems-rfs: dir-add-entry: " \
273                  "block map find failed for ino %lu: %d: %s\n",
274                  rtems_rfs_inode_ino (dir), rc, strerror (rc));
275        break;
276      }
277
278      /*
279       * We have reached the end of the directory so add a block.
280       */
281      rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
282      if (rc > 0)
283      {
284        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
285          printf ("rtems-rfs: dir-add-entry: " \
286                  "block map grow failed for ino %lu: %d: %s\n",
287                  rtems_rfs_inode_ino (dir), rc, strerror (rc));
288        break;
289      }
290
291      read = false;
292    }
293
294    bpos.bno++;
295   
296    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, read);
297    if (rc > 0)
298    {
299      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
300        printf ("rtems-rfs: dir-add-entry: " \
301                "block buffer req failed for ino %lu: %d: %s\n",
302                rtems_rfs_inode_ino (dir), rc, strerror (rc));
303      break;
304    }
305   
306    entry  = rtems_rfs_buffer_data (&buffer);
307   
308    if (!read)
309      memset (entry, 0xff, rtems_rfs_fs_block_size (fs));
310
311    offset = 0;
312   
313    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
314    {
315      rtems_rfs_ino eino;
316      int           elength;
317
318      elength = rtems_rfs_dir_entry_length (entry);
319      eino    = rtems_rfs_dir_entry_ino (entry);
320
321      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
322      {
323        if ((length + RTEMS_RFS_DIR_ENTRY_SIZE) <
324            (rtems_rfs_fs_block_size (fs) - offset))
325        {
326          uint32_t hash;
327          hash = rtems_rfs_dir_hash (name, length);
328          rtems_rfs_dir_set_entry_hash (entry, hash);
329          rtems_rfs_dir_set_entry_ino (entry, ino);
330          rtems_rfs_dir_set_entry_length (entry,
331                                          RTEMS_RFS_DIR_ENTRY_SIZE + length);
332          memcpy (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length);
333          rtems_rfs_buffer_mark_dirty (&buffer);
334          rtems_rfs_buffer_handle_close (fs, &buffer);
335          rtems_rfs_block_map_close (fs, &map);
336          return 0;
337        }
338
339        break;
340      }
341     
342      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
343      {
344        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
345          printf ("rtems-rfs: dir-add-entry: " \
346                  "bad length or ino for ino %lu: %u/%ld @ %04x\n",
347                  rtems_rfs_inode_ino (dir), elength, eino, offset);
348        rtems_rfs_buffer_handle_close (fs, &buffer);
349        rtems_rfs_block_map_close (fs, &map);
350        return EIO;
351      }
352       
353      entry  += elength;
354      offset += elength;
355    }
356  }
357 
358  rtems_rfs_buffer_handle_close (fs, &buffer);
359  rtems_rfs_block_map_close (fs, &map);
360  return rc;
361}
362
363int
364rtems_rfs_dir_del_entry (rtems_rfs_file_system*  fs,
365                         rtems_rfs_inode_handle* dir,
366                         rtems_rfs_ino           ino,
367                         uint32_t                offset)
368{ 
369  rtems_rfs_block_map     map;
370  rtems_rfs_block_no      block;
371  rtems_rfs_buffer_handle buffer;
372  bool                    search;
373  int                     rc;
374
375  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
376    printf ("rtems-rfs: dir-del-entry: dir=%ld, entry=%ld offset=%lu\n",
377            rtems_rfs_inode_ino (dir), ino, offset);
378       
379  rc = rtems_rfs_block_map_open (fs, dir, &map);
380  if (rc > 0)
381    return rc;
382
383  rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
384  if (rc > 0)
385  {
386    if (rc == ENXIO)
387      rc = ENOENT;
388    rtems_rfs_block_map_close (fs, &map);
389    return rc;
390  }
391
392  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
393  if (rc > 0)
394  {
395    rtems_rfs_block_map_close (fs, &map);
396    return rc;
397  }
398
399  /*
400   * Only search if the offset is 0 else we are at that position.
401   */
402  search = offset ? false : true;
403
404  while (rc == 0)
405  {
406    uint8_t* entry;
407    int      offset;
408   
409    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
410    if (rc > 0)
411    {
412      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
413        printf ("rtems-rfs: dir-del-entry: " \
414                "block buffer req failed for ino %lu: %d: %s\n",
415                rtems_rfs_inode_ino (dir), rc, strerror (rc));
416      break;
417    }
418   
419    entry  = rtems_rfs_buffer_data (&buffer);
420    offset = 0;
421   
422    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
423    {
424      rtems_rfs_ino eino;
425      int           elength;
426
427      elength = rtems_rfs_dir_entry_length (entry);
428      eino    = rtems_rfs_dir_entry_ino (entry);
429
430      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
431        break;
432     
433      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
434      {
435        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
436          printf ("rtems-rfs: dir-del-entry: " \
437                  "bad length or ino for ino %lu: %u/%ld @ %04x\n",
438                  rtems_rfs_inode_ino (dir), elength, eino, offset);
439        rc = EIO;
440        break;
441      }
442       
443      if (ino == rtems_rfs_dir_entry_ino (entry))
444      {
445        uint32_t remaining;
446        remaining = rtems_rfs_fs_block_size (fs) - (offset + elength);
447        memmove (entry, entry + elength, remaining);
448        memset (entry + remaining, 0xff, elength);
449
450        /*
451         * If the remainder of the block is empty and this is the start of the
452         * block and it is the last block in the map shrink the map.
453         *
454         * @note We could check again to see if the new end block in the map is
455         *       also empty. This way we could clean up an empty directory.
456         */
457        elength = rtems_rfs_dir_entry_length (entry);
458
459        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
460          printf ("rtems-rfs: dir-del-entry: " \
461                  "last block free for ino %lu: elength=%i offset=%d last=%s\n",
462                  ino, elength, offset,
463                  rtems_rfs_block_map_last (&map) ? "yes" : "no");
464
465        if ((elength == RTEMS_RFS_DIR_ENTRY_EMPTY) &&
466            (offset == 0) && rtems_rfs_block_map_last (&map))
467        {
468          rc = rtems_rfs_block_map_shrink (fs, &map, 1);
469          if (rc > 0)
470          {
471            if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
472              printf ("rtems-rfs: dir-del-entry: " \
473                      "block map shrink failed for ino %lu: %d: %s\n",
474                      rtems_rfs_inode_ino (dir), rc, strerror (rc));
475          }
476        }
477       
478        rtems_rfs_buffer_mark_dirty (&buffer);
479        rtems_rfs_buffer_handle_close (fs, &buffer);
480        rtems_rfs_block_map_close (fs, &map);
481        return 0;
482      }
483
484      if (!search)
485      {
486        rc = EIO;
487        break;
488      }
489     
490      entry  += elength;
491      offset += elength;
492    }
493
494    if (rc == 0)
495    {
496      rc = rtems_rfs_block_map_next_block (fs, &map, &block);
497      if (rc == ENXIO)
498        rc = ENOENT;
499    }
500  }
501 
502  rtems_rfs_buffer_handle_close (fs, &buffer);
503  rtems_rfs_block_map_close (fs, &map);
504  return rc;
505}
506
507int
508rtems_rfs_dir_read (rtems_rfs_file_system*  fs,
509                    rtems_rfs_inode_handle* dir,
510                    rtems_rfs_pos_rel       offset,
511                    struct dirent*          dirent,
512                    size_t*                 length)
513{
514  rtems_rfs_block_map     map;
515  rtems_rfs_buffer_handle buffer;
516  rtems_rfs_block_no      block;
517  int                     rc;
518
519  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
520    printf ("rtems-rfs: dir-read: dir=%ld offset=%Ld\n",
521            rtems_rfs_inode_ino (dir), offset);
522
523  *length = 0;
524 
525  rc = rtems_rfs_block_map_open (fs, dir, &map);
526  if (rc > 0)
527    return rc;
528
529  if (((rtems_rfs_fs_block_size (fs) -
530        (offset % rtems_rfs_fs_block_size (fs))) <= RTEMS_RFS_DIR_ENTRY_SIZE))
531    offset = (((offset / rtems_rfs_fs_block_size (fs)) + 1) *
532              rtems_rfs_fs_block_size (fs));
533 
534  rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
535  if (rc > 0)
536  {
537    if (rc == ENXIO)
538      rc = ENOENT;
539    rtems_rfs_block_map_close (fs, &map);
540    return rc;
541  }
542 
543  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
544  if (rc > 0)
545  {
546    rtems_rfs_block_map_close (fs, &map);
547    return rc;
548  }
549
550  /*
551   * Look for an empty entry and if this is the last block that is the end of
552   * the directory.
553   */
554  while (rc == 0)
555  {
556    uint8_t*      entry;
557    rtems_rfs_ino eino;
558    int           elength;   
559    int           remaining;
560   
561    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
562    if (rc > 0)
563    {
564      rtems_rfs_buffer_handle_close (fs, &buffer);
565      rtems_rfs_block_map_close (fs, &map);
566      return rc;
567    }
568
569    entry  = rtems_rfs_buffer_data (&buffer);
570    entry += map.bpos.boff;
571   
572    elength = rtems_rfs_dir_entry_length (entry);
573    eino    = rtems_rfs_dir_entry_ino (entry);
574
575    if (elength != RTEMS_RFS_DIR_ENTRY_EMPTY)
576    {
577      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
578      {
579        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
580          printf ("rtems-rfs: dir-read: " \
581                  "bad length or ino for ino %lu: %u/%ld @ %04lx\n",
582                  rtems_rfs_inode_ino (dir), elength, eino, map.bpos.boff);
583        rc = EIO;
584        break;
585      }
586       
587      memset (dirent, 0, sizeof (struct dirent));
588      dirent->d_off = offset;
589      dirent->d_reclen = sizeof (struct dirent);
590
591      *length += elength;
592
593      remaining = rtems_rfs_fs_block_size (fs) - (map.bpos.boff + elength);
594     
595      if (remaining <= RTEMS_RFS_DIR_ENTRY_SIZE)
596        *length += remaining;
597     
598      if (elength < RTEMS_RFS_DIR_ENTRY_SIZE)
599        elength = 0;
600      else
601        elength -= RTEMS_RFS_DIR_ENTRY_SIZE;
602      if (elength > NAME_MAX)
603        elength = NAME_MAX;
604     
605      memcpy (dirent->d_name, entry + RTEMS_RFS_DIR_ENTRY_SIZE, elength);
606
607      dirent->d_ino = rtems_rfs_dir_entry_ino (entry);
608      dirent->d_namlen = elength;
609     
610      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
611        printf ("rtems-rfs: dir-read: found off:%Ld ino:%ld name=%s\n",
612                dirent->d_off, dirent->d_ino, dirent->d_name);
613      break;
614    }
615
616    *length += rtems_rfs_fs_block_size (fs) - map.bpos.boff;
617   
618    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
619      printf ("rtems-rfs: dir-read: next block: off:%ld length:%zd\n",
620              (uint32_t) offset, *length);
621     
622    rc = rtems_rfs_block_map_next_block (fs, &map, &block);
623    if (rc == ENXIO)
624      rc = ENOENT;
625  }
626
627  rtems_rfs_buffer_handle_close (fs, &buffer);
628  rtems_rfs_block_map_close (fs, &map);
629  return rc;
630}
631
632int
633rtems_rfs_dir_empty (rtems_rfs_file_system*  fs,
634                     rtems_rfs_inode_handle* dir)
635{
636  rtems_rfs_block_map     map;
637  rtems_rfs_buffer_handle buffer;
638  rtems_rfs_block_no      block;
639  bool                    empty;
640  int                     rc;
641
642  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
643    printf ("rtems-rfs: dir-empty: dir=%ld\n", rtems_rfs_inode_ino (dir));
644
645  empty = true;
646 
647  rc = rtems_rfs_block_map_open (fs, dir, &map);
648  if (rc > 0)
649    return rc;
650
651  rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
652  if (rc > 0)
653  {
654    rtems_rfs_block_map_close (fs, &map);
655    return rc;
656  }
657 
658  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
659  if (rc > 0)
660  {
661    rtems_rfs_block_map_close (fs, &map);
662    return rc;
663  }
664
665  /*
666   * Look for an empty entry and if this is the last block that is the end of
667   * the directory.
668   */
669  while (empty)
670  {
671    uint8_t* entry;
672    int      offset;
673   
674    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
675    if (rc > 0)
676      break;
677
678    entry  = rtems_rfs_buffer_data (&buffer);
679    offset = 0;
680   
681    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
682    {
683      rtems_rfs_ino eino;
684      int           elength;
685
686      elength = rtems_rfs_dir_entry_length (entry);
687      eino    = rtems_rfs_dir_entry_ino (entry);
688
689      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
690        break;
691
692      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
693      {
694        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_EMPTY))
695          printf ("rtems-rfs: dir-empty: " \
696                  "bad length or ino for ino %lu: %u/%ld @ %04x\n",
697                  rtems_rfs_inode_ino (dir), elength, eino, offset);
698        rc = EIO;
699        break;
700      }
701       
702      /*
703       * Ignore the current (.) and parent (..) entries. Anything else means
704       * the directory is not empty.
705       */
706      if (((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 1)) ||
707           (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.')) &&
708          ((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 2)) ||
709           (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.') ||
710           (entry[RTEMS_RFS_DIR_ENTRY_SIZE + 1] != '.')))
711      {
712        empty = false;
713        break;
714      }
715
716      entry  += elength;
717      offset += elength;
718    }
719
720    if (empty)
721    {
722      rc = rtems_rfs_block_map_next_block (fs, &map, &block);
723      if (rc > 0)
724      {
725        if (rc == ENXIO)
726          rc = 0;
727        break;
728      }
729    }
730  }
731
732  if ((rc == 0) && !empty)
733    rc = ENOTEMPTY;
734 
735  rtems_rfs_buffer_handle_close (fs, &buffer);
736  rtems_rfs_block_map_close (fs, &map);
737  return rc;
738}
Note: See TracBrowser for help on using the repository browser.