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

4.115
Last change on this file since e3865876 was e3865876, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/06/11 at 07:08:32

2011-11-06 Ralf Corsépius <ralf.corsepius@…>

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