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

4.115
Last change on this file since 9a783b71 was 9a783b71, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/15/10 at 23:34:56

2010-06-15 Ralf Corsépius <ralf.corsepius@…>

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