source: rtems/cpukit/libfs/src/rfs/rtems-rfs-file.c @ 3cfa636

4.104.11
Last change on this file since 3cfa636 was 3cfa636, checked in by Chris Johns <chrisj@…>, on Feb 26, 2010 at 5:54:59 AM

010-02-26 Chris Johns <chrisj@…>

  • libfs/src/rfs/rtems-rfs-block.c: Reset a buffer handle after moving down an indirection level.
  • libfs/src/rfs/rtems-rfs-dir.c: Move directory entry validation into a macro and use the macro. Fix the range check on the ino so all inodes can be used.
  • libfs/src/rfs/rtems-rfs-file-system.c,
libfs/src/rfs/rtems-rfs-file-system.h
Add a version number to the superblock. Use RTEMS_RFS_INODE_SIZE.
  • libfs/src/rfs/rtems-rfs-file.c: Fix the size offset on partial block lengths. Set the size in the file handle on a truncate to 0.
  • libfs/src/rfs/rtems-rfs-format.c: Add a version number to the superblock. Use RTEMS_RFS_INODE_SIZE. A better set of defaults for small disks.
  • libfs/src/rfs/rtems-rfs-inode.c: Use RTEMS_RFS_INODE_SIZE. Free the allocated inode if it cannot be opened.
  • libfs/src/rfs/rtems-rfs-inode.h: Add RTEMS_RFS_INODE_SIZE.
  • libfs/src/rfs/rtems-rfs-rtems-file.c: Move some of the iop acceses inside the fs lock.
  • libfs/src/rfs/rtems-rfs-shell.c: Use RTEMS_RFS_INODE_SIZE.
  • Property mode set to 100644
File size: 16.9 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 File Routines.
16 *
17 * These functions manage files.
18 */
19
20#include <rtems/rfs/rtems-rfs-block-pos.h>
21#include <rtems/rfs/rtems-rfs-file.h>
22#include <rtems/rfs/rtems-rfs-file-system.h>
23#include <rtems/rfs/rtems-rfs-trace.h>
24
25int
26rtems_rfs_file_open (rtems_rfs_file_system*  fs,
27                     rtems_rfs_ino           ino,
28                     uint32_t                flags,
29                     rtems_rfs_file_handle** file)
30{
31  rtems_rfs_file_handle* handle;
32  rtems_rfs_file_shared* shared;
33  int                    rc;
34
35  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
36    printf ("rtems-rfs: file-open: ino=%ld\n", ino);
37           
38  *file = NULL;
39
40  /*
41   * Allocate a new handle and initialise it. Do this before we deal with the
42   * shared node data so we do not have to be concerned with reference
43   * counting.
44   */
45  handle = malloc (sizeof (rtems_rfs_file_handle));
46  if (!handle)
47    return ENOMEM;
48
49  memset (handle, 0, sizeof (rtems_rfs_file_handle));
50
51  rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer);
52  if (rc > 0)
53  {
54    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
55      printf ("rtems-rfs: file-open: buffer handle open failed: %d: %s\n",
56              rc, strerror (rc));
57    free (handle);
58    return rc;
59  }
60 
61  /*
62   * Scan the file system data list of open files for this ino. If found up
63   * the reference count and return the pointer to the data.
64   */
65  shared = rtems_rfs_file_get_shared (fs, ino);
66  if (shared)
67  {
68    shared->references++;
69    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
70      printf ("rtems-rfs: file-open: ino=%ld shared\n", ino);
71  }
72  else
73  {
74    /*
75     * None exists so create. Copy in the shared parts of the inode we hold in
76     * memory.
77     */
78    shared = malloc (sizeof (rtems_rfs_file_shared));
79    if (!shared)
80    {
81      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
82      free (handle);
83      return ENOMEM;
84    }
85
86    memset (shared, 0, sizeof (rtems_rfs_file_shared));
87   
88    rc = rtems_rfs_inode_open (fs, ino, &shared->inode, true);
89    if (rc > 0)
90    {
91      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
92        printf ("rtems-rfs: file-open: inode open failed: %d: %s\n",
93                rc, strerror (rc));
94      free (shared);
95      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
96      free (handle);
97      return rc;
98    }
99
100    rc = rtems_rfs_block_map_open (fs, &shared->inode, &shared->map);
101    if (rc > 0)
102    {
103      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
104        printf ("rtems-rfs: file-open: block map open failed: %d: %s\n",
105                rc, strerror (rc));
106      rtems_rfs_inode_close (fs, &shared->inode);
107      free (shared);
108      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
109      free (handle);
110      return rc;
111    }
112
113    shared->references = 1;
114    shared->size.count = rtems_rfs_inode_get_block_count (&shared->inode);
115    shared->size.offset = rtems_rfs_inode_get_block_offset (&shared->inode);
116    shared->atime = rtems_rfs_inode_get_atime (&shared->inode);
117    shared->mtime = rtems_rfs_inode_get_mtime (&shared->inode);
118    shared->ctime = rtems_rfs_inode_get_ctime (&shared->inode);
119    shared->fs = fs;
120
121    rtems_chain_append (&fs->file_shares, &shared->link);
122
123    rtems_rfs_inode_unload (fs, &shared->inode, false);
124
125    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
126      printf ("rtems-rfs: file-open: ino=%ld share created\n", ino);
127  }
128
129  handle->flags  = flags;
130  handle->shared = shared;
131 
132  *file = handle;
133 
134  return 0;
135}
136
137int
138rtems_rfs_file_close (rtems_rfs_file_system* fs,
139                      rtems_rfs_file_handle* handle)
140{
141  int rrc;
142  int rc;
143
144  rrc = 0;
145 
146  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
147    printf ("rtems-rfs: file-close: entry: ino=%ld\n",
148            handle->shared->inode.ino);
149
150  if (handle->shared->references > 0)
151    handle->shared->references--;
152
153  if (handle->shared->references == 0)
154  {
155    /*
156     * @todo This could be clever and only update if different.
157     */
158    rtems_rfs_inode_set_atime (&handle->shared->inode,
159                               handle->shared->atime);
160    rtems_rfs_inode_set_mtime (&handle->shared->inode,
161                               handle->shared->mtime);
162    rtems_rfs_inode_set_ctime (&handle->shared->inode,
163                               handle->shared->ctime);
164    handle->shared->map.size.count = handle->shared->size.count;
165    handle->shared->map.size.offset = handle->shared->size.offset;
166
167    rc = rtems_rfs_block_map_close (fs, &handle->shared->map);
168    if (rc > 0)
169    {
170      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
171        printf ("rtems-rfs: file-close: map close error: ino=%ld: %d: %s\n",
172                handle->shared->inode.ino, rc, strerror (rc));
173      if (rrc == 0)
174        rrc = rc;
175    }
176   
177    rc = rtems_rfs_inode_close (fs, &handle->shared->inode);
178    if (rc > 0)
179    {
180      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
181        printf ("rtems-rfs: file-close: inode close error: ino=%ld: %d: %s\n",
182                handle->shared->inode.ino, rc, strerror (rc));
183      if (rrc == 0)
184        rrc = rc;
185    }
186   
187    rtems_chain_extract (&handle->shared->link);
188    free (handle->shared);
189  }
190
191  rc = rtems_rfs_buffer_handle_close (fs, &handle->buffer);
192  if ((rrc == 0) && (rc > 0))
193    rrc = rc;
194 
195  if (rrc > 0)
196  {
197    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
198      printf ("rtems-rfs: file-close: result: %d: %s\n", rrc, strerror (rrc));
199  }
200
201  free (handle);
202 
203  return rrc;
204}
205
206int
207rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
208                         size_t*                available,
209                         bool                   read)
210{
211  size_t size;
212 
213  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
214    printf ("rtems-rfs: file-io: start: %s pos=%lu:%lu\n",
215            read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);
216 
217  if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
218  {
219    rtems_rfs_buffer_block block;
220    bool                   request_read;
221    int                    rc;
222     
223    request_read = read;
224   
225    rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
226                                   rtems_rfs_file_map (handle),
227                                   rtems_rfs_file_bpos (handle),
228                                   &block);
229    if (rc > 0)
230    {
231      /*
232       * Has the read reached the EOF ?
233       */
234      if (read && (rc == ENXIO))
235      {
236        *available = 0;
237        return 0;
238      }
239     
240      if (rc != ENXIO)
241        return rc;
242
243      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
244        printf ("rtems-rfs: file-io: start: grow\n");
245     
246      rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
247                                     rtems_rfs_file_map (handle),
248                                     1, &block);
249      if (rc > 0)
250        return rc;
251
252      request_read = false;
253    }
254    else
255    {
256      /*
257       * If this is a write check if the write starts within a block or the
258       * amount of data is less than a block size. If it is read the block
259       * rather than getting a block to fill.
260       */
261      if (!read &&
262          (rtems_rfs_file_block_offset (handle) ||
263           (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
264        request_read = true;
265    }
266   
267    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
268      printf ("rtems-rfs: file-io: start: block=%lu request-read=%s\n",
269              block, request_read ? "yes" : "no");
270   
271    rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
272                                          rtems_rfs_file_buffer (handle),
273                                          block, request_read);
274    if (rc > 0)
275      return rc;
276  }
277 
278  if (read
279      && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
280      && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
281    size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
282  else
283    size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
284 
285  *available = size - rtems_rfs_file_block_offset (handle);
286
287  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
288    printf ("rtems-rfs: file-io: start: available=%lu (%lu)\n",
289            *available, size);
290   
291  return 0;
292}
293
294int
295rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
296                       size_t                 size,
297                       bool                   read)
298{
299  bool atime;
300  bool mtime;
301  bool length;
302  int  rc = 0;
303
304  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
305    printf ("rtems-rfs: file-io:   end: %s size=%lu\n",
306            read ? "read" : "write", size);
307 
308  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
309  {
310    if (!read)
311      rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
312    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
313                                          rtems_rfs_file_buffer (handle));
314    if (rc > 0)
315    {
316      printf ("rtems-rfs: file-io:   end: error on release: %s size=%lu: %d: %s\n",
317              read ? "read" : "write", size, rc, strerror (rc));
318     
319      return rc;
320    }
321  }
322
323  /*
324   * Update the handle's position. Only a block size can be handled at a time
325   * so no special maths is needed. If the offset is bigger than the block size
326   * increase the block number and adjust the offset.
327   *
328   * If we are the last block and the position is past the current size update
329   * the size with the new length. The map holds the block count.
330   */
331  handle->bpos.boff += size;
332
333  if (handle->bpos.boff >=
334      rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
335  {
336    handle->bpos.bno++;
337    handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
338  }
339
340  length = false;
341  mtime = false;
342 
343  if (!read &&
344      rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
345                                    rtems_rfs_file_bpos (handle)))
346  {
347    rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
348                                         handle->bpos.boff);
349    length = true;
350    mtime = true;
351  }
352 
353  atime  = rtems_rfs_file_update_atime (handle);
354  mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
355  length = rtems_rfs_file_update_length (handle) && length;
356 
357  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
358    printf ("rtems-rfs: file-io:   end: pos=%lu:%lu %c %c %c\n",
359            handle->bpos.bno, handle->bpos.boff,
360            atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
361 
362  if (atime || mtime)
363  {
364    time_t now = time (NULL);
365    if (read && atime)
366      handle->shared->atime = now;
367    if (!read && mtime)
368      handle->shared->mtime = now;
369  }
370  if (length)
371  {
372    handle->shared->size.count =
373      rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
374    handle->shared->size.offset =
375      rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
376  }
377 
378  return rc;
379}
380
381int
382rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
383{
384  int rc = 0;
385  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
386    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
387                                          rtems_rfs_file_buffer (handle));
388  return rc;
389}
390
391int
392rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
393                     rtems_rfs_pos          pos,
394                     rtems_rfs_pos*         new_pos)
395{
396  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
397    printf ("rtems-rfs: file-seek: new=%Lu\n", pos);
398 
399  /*
400   * This call only sets the position if it is in a valid part of the file. The
401   * user can request past the end of the file then write to extend the
402   * file. The lseek entry states:
403   *
404   *    "Although lseek() may position the file offset beyond the end of the
405   *     file, this function does not itself extend the size of the file."
406   *
407   * This means the file needs to set the file size to the pos only when a
408   * write occurs.
409   */
410  if (pos <= rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
411                                             handle->shared))
412    rtems_rfs_file_set_bpos (handle, pos);
413 
414  *new_pos = pos;
415  return 0;
416}
417
418int
419rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
420                         rtems_rfs_pos          new_size)
421{
422  rtems_rfs_block_map* map  = rtems_rfs_file_map (handle);
423  rtems_rfs_pos        size;
424  int                  rc;
425
426  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
427    printf ("rtems-rfs: file-set-size: size=%Lu\n", new_size);
428
429  /*
430   * Short cut for the common truncate on open call.
431   */
432  if (new_size == 0)
433  {
434    rc = rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
435    if (rc > 0)
436      return rc;
437  }
438  else
439  {
440    size = rtems_rfs_file_size (handle);
441 
442    /*
443     * If the file is same size do nothing else grow or shrink it ?
444     */
445    if (size != new_size)
446    {
447      if (size < new_size)
448      {
449        /*
450         * Grow. Fill with 0's.
451         */
452        rtems_rfs_pos count;
453        uint32_t      length;
454        bool          read_block;
455
456        count = new_size - size;
457        length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
458        read_block = false;
459       
460        while (count)
461        {
462          rtems_rfs_buffer_block block;
463          rtems_rfs_block_pos    bpos;
464          uint8_t*               dst;
465
466          /*
467           * Get the block position for the current end of the file as seen by
468           * the map. If not found and the EOF grow the map then fill the block
469           * with 0.
470           */
471          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
472          rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
473                                         map, &bpos, &block);
474          if (rc > 0)
475          {
476            /*
477             * Have we reached the EOF ?
478             */
479            if (rc != ENXIO)
480              return rc;
481
482            rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
483                                           map, 1, &block);
484            if (rc > 0)
485              return rc;
486          }
487
488          if (count < (length - bpos.boff))
489          {
490            length = count + bpos.boff;
491            read_block = true;
492            rtems_rfs_block_map_set_size_offset (map, length);
493          }
494          else
495          {
496            rtems_rfs_block_map_set_size_offset (map, 0);
497          }
498
499          /*
500           * Only read the block if the length is not the block size.
501           */
502          rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
503                                                rtems_rfs_file_buffer (handle),
504                                                block, read_block);
505          if (rc > 0)
506            return rc;
507
508          dst = rtems_rfs_buffer_data (&handle->buffer);
509          memset (dst + bpos.boff, 0, length - bpos.boff);
510
511          rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
512
513          rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
514                                                rtems_rfs_file_buffer (handle));
515          if (rc > 0)
516            return rc;
517       
518          count -= length - bpos.boff;
519        }
520      }
521      else
522      {
523        /*
524         * Shrink
525         */
526        rtems_rfs_block_no blocks;
527        uint32_t           offset;
528   
529        blocks =
530          rtems_rfs_block_map_count (map) -
531          (((new_size - 1) /
532            rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);
533
534        offset =
535          new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
536     
537        if (blocks)
538        {
539          int rc;
540          rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
541                                           rtems_rfs_file_map (handle),
542                                           blocks);
543          if (rc > 0)
544            return rc;
545        }
546
547        rtems_rfs_block_map_set_size_offset (map, offset);
548
549        if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
550                                          rtems_rfs_block_map_size (map)))
551          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
552                                         rtems_rfs_file_bpos (handle));
553      }
554    }
555  }
556
557  handle->shared->size.count  = rtems_rfs_block_map_count (map);
558  handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);
559
560  if (rtems_rfs_file_update_mtime (handle))
561    handle->shared->mtime = time (NULL);
562 
563  return 0;
564}
565
566rtems_rfs_file_shared*
567rtems_rfs_file_get_shared (rtems_rfs_file_system* fs,
568                           rtems_rfs_ino          ino)
569{
570  rtems_chain_node* node;
571  node = rtems_chain_first (&fs->file_shares);
572  while (!rtems_chain_is_tail (&fs->file_shares, node))
573  {
574    rtems_rfs_file_shared* shared;
575    shared = (rtems_rfs_file_shared*) node;
576    if (shared->inode.ino == ino)
577      return shared;
578    node = rtems_chain_next (node);
579  }
580  return NULL;
581}
Note: See TracBrowser for help on using the repository browser.