source: rtems/cpukit/libfs/src/rfs/rtems-rfs-file.c @ 6ed22ab

4.115
Last change on this file since 6ed22ab was 6ed22ab, checked in by Chris Johns <chrisj@…>, on 08/26/10 at 06:31:15

2010-08-26 Chris Johns <chrisj@…>

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