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

5
Last change on this file since d0a7f03 was d0a7f03, checked in by Jacob Shin <jacobshin313@…>, on 12/03/18 at 03:13:23

5 spelling errors for a Google Code-In task.

Username: deuteriumoxide Email: jacobshin313@…

  • 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 without 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.