source: rtems/cpukit/libfs/src/rfs/rtems-rfs-file.c @ 90cb370

4.10
Last change on this file since 90cb370 was 90cb370, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/16/10 at 17:43:57

2010-06-16 Ralf Corsépius <ralf.corsepius@…>

  • libfs/src/rfs/rtems-rfs-file.c: Various 64bit fixes.
  • Property mode set to 100644
File size: 17.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 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    /*
162     * @todo This could be clever and only update if different.
163     */
164    rtems_rfs_inode_set_atime (&handle->shared->inode,
165                               handle->shared->atime);
166    rtems_rfs_inode_set_mtime (&handle->shared->inode,
167                               handle->shared->mtime);
168    rtems_rfs_inode_set_ctime (&handle->shared->inode,
169                               handle->shared->ctime);
170    handle->shared->map.size.count = handle->shared->size.count;
171    handle->shared->map.size.offset = handle->shared->size.offset;
172
173    rc = rtems_rfs_block_map_close (fs, &handle->shared->map);
174    if (rc > 0)
175    {
176      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
177        printf ("rtems-rfs: file-close: map close error: ino=%" PRId32 ": %d: %s\n",
178                handle->shared->inode.ino, rc, strerror (rc));
179      if (rrc == 0)
180        rrc = rc;
181    }
182   
183    rc = rtems_rfs_inode_close (fs, &handle->shared->inode);
184    if (rc > 0)
185    {
186      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
187        printf ("rtems-rfs: file-close: inode close error: ino=%" PRId32 ": %d: %s\n",
188                handle->shared->inode.ino, rc, strerror (rc));
189      if (rrc == 0)
190        rrc = rc;
191    }
192   
193    rtems_chain_extract (&handle->shared->link);
194    free (handle->shared);
195  }
196
197  rc = rtems_rfs_buffer_handle_close (fs, &handle->buffer);
198  if ((rrc == 0) && (rc > 0))
199    rrc = rc;
200 
201  if (rrc > 0)
202  {
203    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
204      printf ("rtems-rfs: file-close: result: %d: %s\n", rrc, strerror (rrc));
205  }
206
207  free (handle);
208 
209  return rrc;
210}
211
212int
213rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
214                         size_t*                available,
215                         bool                   read)
216{
217  size_t size;
218 
219  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
220    printf ("rtems-rfs: file-io: start: %s pos=%" PRIu32 ":%" PRIu32 "\n",
221            read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);
222 
223  if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
224  {
225    rtems_rfs_buffer_block block;
226    bool                   request_read;
227    int                    rc;
228     
229    request_read = read;
230   
231    rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
232                                   rtems_rfs_file_map (handle),
233                                   rtems_rfs_file_bpos (handle),
234                                   &block);
235    if (rc > 0)
236    {
237      /*
238       * Has the read reached the EOF ?
239       */
240      if (read && (rc == ENXIO))
241      {
242        *available = 0;
243        return 0;
244      }
245     
246      if (rc != ENXIO)
247        return rc;
248
249      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
250        printf ("rtems-rfs: file-io: start: grow\n");
251     
252      rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
253                                     rtems_rfs_file_map (handle),
254                                     1, &block);
255      if (rc > 0)
256        return rc;
257
258      request_read = false;
259    }
260    else
261    {
262      /*
263       * If this is a write check if the write starts within a block or the
264       * amount of data is less than a block size. If it is read the block
265       * rather than getting a block to fill.
266       */
267      if (!read &&
268          (rtems_rfs_file_block_offset (handle) ||
269           (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
270        request_read = true;
271    }
272   
273    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
274      printf ("rtems-rfs: file-io: start: block=%" PRIu32 " request-read=%s\n",
275              block, request_read ? "yes" : "no");
276   
277    rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
278                                          rtems_rfs_file_buffer (handle),
279                                          block, request_read);
280    if (rc > 0)
281      return rc;
282  }
283 
284  if (read
285      && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
286      && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
287    size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
288  else
289    size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
290 
291  *available = size - rtems_rfs_file_block_offset (handle);
292
293  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
294    printf ("rtems-rfs: file-io: start: available=%zu (%zu)\n",
295            *available, size);
296   
297  return 0;
298}
299
300int
301rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
302                       size_t                 size,
303                       bool                   read)
304{
305  bool atime;
306  bool mtime;
307  bool length;
308  int  rc = 0;
309
310  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
311    printf ("rtems-rfs: file-io:   end: %s size=%zu\n",
312            read ? "read" : "write", size);
313 
314  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
315  {
316    if (!read)
317      rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
318    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
319                                          rtems_rfs_file_buffer (handle));
320    if (rc > 0)
321    {
322      printf (
323        "rtems-rfs: file-io:   end: error on release: %s size=%zu: %d: %s\n",
324        read ? "read" : "write", size, rc, strerror (rc));
325     
326      return rc;
327    }
328  }
329
330  /*
331   * Update the handle's position. Only a block size can be handled at a time
332   * so no special maths is needed. If the offset is bigger than the block size
333   * increase the block number and adjust the offset.
334   *
335   * If we are the last block and the position is past the current size update
336   * the size with the new length. The map holds the block count.
337   */
338  handle->bpos.boff += size;
339
340  if (handle->bpos.boff >=
341      rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
342  {
343    handle->bpos.bno++;
344    handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
345  }
346
347  length = false;
348  mtime = false;
349 
350  if (!read &&
351      rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
352                                    rtems_rfs_file_bpos (handle)))
353  {
354    rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
355                                         handle->bpos.boff);
356    length = true;
357    mtime = true;
358  }
359 
360  atime  = rtems_rfs_file_update_atime (handle);
361  mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
362  length = rtems_rfs_file_update_length (handle) && length;
363 
364  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
365    printf ("rtems-rfs: file-io:   end: pos=%" PRIu32 ":%" PRIu32 " %c %c %c\n",
366            handle->bpos.bno, handle->bpos.boff,
367            atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
368 
369  if (atime || mtime)
370  {
371    time_t now = time (NULL);
372    if (read && atime)
373      handle->shared->atime = now;
374    if (!read && mtime)
375      handle->shared->mtime = now;
376  }
377  if (length)
378  {
379    handle->shared->size.count =
380      rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
381    handle->shared->size.offset =
382      rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
383  }
384 
385  return rc;
386}
387
388int
389rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
390{
391  int rc = 0;
392  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
393    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
394                                          rtems_rfs_file_buffer (handle));
395  return rc;
396}
397
398int
399rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
400                     rtems_rfs_pos          pos,
401                     rtems_rfs_pos*         new_pos)
402{
403  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
404    printf ("rtems-rfs: file-seek: new=%" PRIu64 "\n", pos);
405 
406  /*
407   * This call only sets the position if it is in a valid part of the file. The
408   * user can request past the end of the file then write to extend the
409   * file. The lseek entry states:
410   *
411   *    "Although lseek() may position the file offset beyond the end of the
412   *     file, this function does not itself extend the size of the file."
413   *
414   * This means the file needs to set the file size to the pos only when a
415   * write occurs.
416   */
417  if (pos <= rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
418                                             handle->shared))
419    rtems_rfs_file_set_bpos (handle, pos);
420 
421  *new_pos = pos;
422  return 0;
423}
424
425int
426rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
427                         rtems_rfs_pos          new_size)
428{
429  rtems_rfs_block_map* map  = rtems_rfs_file_map (handle);
430  rtems_rfs_pos        size;
431  int                  rc;
432
433  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
434    printf ("rtems-rfs: file-set-size: size=%" PRIu64 "\n", new_size);
435
436  /*
437   * Short cut for the common truncate on open call.
438   */
439  if (new_size == 0)
440  {
441    rc = rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
442    if (rc > 0)
443      return rc;
444  }
445  else
446  {
447    size = rtems_rfs_file_size (handle);
448 
449    /*
450     * If the file is same size do nothing else grow or shrink it ?
451     */
452    if (size != new_size)
453    {
454      if (size < new_size)
455      {
456        /*
457         * Grow. Fill with 0's.
458         */
459        rtems_rfs_pos count;
460        uint32_t      length;
461        bool          read_block;
462
463        count = new_size - size;
464        length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
465        read_block = false;
466       
467        while (count)
468        {
469          rtems_rfs_buffer_block block;
470          rtems_rfs_block_pos    bpos;
471          uint8_t*               dst;
472
473          /*
474           * Get the block position for the current end of the file as seen by
475           * the map. If not found and the EOF grow the map then fill the block
476           * with 0.
477           */
478          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
479          rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
480                                         map, &bpos, &block);
481          if (rc > 0)
482          {
483            /*
484             * Have we reached the EOF ?
485             */
486            if (rc != ENXIO)
487              return rc;
488
489            rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
490                                           map, 1, &block);
491            if (rc > 0)
492              return rc;
493          }
494
495          if (count < (length - bpos.boff))
496          {
497            length = count + bpos.boff;
498            read_block = true;
499            rtems_rfs_block_map_set_size_offset (map, length);
500          }
501          else
502          {
503            rtems_rfs_block_map_set_size_offset (map, 0);
504          }
505
506          /*
507           * Only read the block if the length is not the block size.
508           */
509          rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
510                                                rtems_rfs_file_buffer (handle),
511                                                block, read_block);
512          if (rc > 0)
513            return rc;
514
515          dst = rtems_rfs_buffer_data (&handle->buffer);
516          memset (dst + bpos.boff, 0, length - bpos.boff);
517
518          rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
519
520          rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
521                                                rtems_rfs_file_buffer (handle));
522          if (rc > 0)
523            return rc;
524       
525          count -= length - bpos.boff;
526        }
527      }
528      else
529      {
530        /*
531         * Shrink
532         */
533        rtems_rfs_block_no blocks;
534        uint32_t           offset;
535   
536        blocks =
537          rtems_rfs_block_map_count (map) -
538          (((new_size - 1) /
539            rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);
540
541        offset =
542          new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
543     
544        if (blocks)
545        {
546          int rc;
547          rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
548                                           rtems_rfs_file_map (handle),
549                                           blocks);
550          if (rc > 0)
551            return rc;
552        }
553
554        rtems_rfs_block_map_set_size_offset (map, offset);
555
556        if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
557                                          rtems_rfs_block_map_size (map)))
558          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
559                                         rtems_rfs_file_bpos (handle));
560      }
561    }
562  }
563
564  handle->shared->size.count  = rtems_rfs_block_map_count (map);
565  handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);
566
567  if (rtems_rfs_file_update_mtime (handle))
568    handle->shared->mtime = time (NULL);
569 
570  return 0;
571}
572
573rtems_rfs_file_shared*
574rtems_rfs_file_get_shared (rtems_rfs_file_system* fs,
575                           rtems_rfs_ino          ino)
576{
577  rtems_chain_node* node;
578  node = rtems_chain_first (&fs->file_shares);
579  while (!rtems_chain_is_tail (&fs->file_shares, node))
580  {
581    rtems_rfs_file_shared* shared;
582    shared = (rtems_rfs_file_shared*) node;
583    if (shared->inode.ino == ino)
584      return shared;
585    node = rtems_chain_next (node);
586  }
587  return NULL;
588}
Note: See TracBrowser for help on using the repository browser.