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

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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