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

5
Last change on this file since 0ec9bbc was d869c182, checked in by Fan Deng <enetor@…>, on 10/10/17 at 23:32:41

Fill in the correct d_off in rtems_rfs_dir_read.

rtems_rfs_dir_read searches the directory inode's entries list starting
at the specified offset until an empty entry (last entry) is encountered. It
fills in a struct dirent with the name of the entry, length of the name, ino of
the entry, and the absolute offset of the entry in the parent directory's
entries
list.

Unfortunately, the stock implementation of rtems_rfs_dir_read returns a
somewhat arbitrary offset (as dirent::d_off), while
rtems_rfs_dir_lookup_ino always returns the correct offset.

This change fixes that logic so the returned offset is accurate.

Tested by comparing the offset returned in dirent with the result of
rtems_rfs_dir_lookup_ino.

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