source: rtems/cpukit/libfs/src/rfs/rtems-rfs-dir.c @ 3cfa636

4.104.11
Last change on this file since 3cfa636 was 3cfa636, checked in by Chris Johns <chrisj@…>, on Feb 26, 2010 at 5:54:59 AM

010-02-26 Chris Johns <chrisj@…>

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