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

4.104.11
Last change on this file since 59762963 was 59762963, checked in by Chris Johns <chrisj@…>, on Feb 22, 2010 at 11:02:41 PM

2010-02-23 Chris Johns <chrisj@…>

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