source: rtems/cpukit/libfs/src/rfs/rtems-rfs-link.c @ 0ec9bbc

5
Last change on this file since 0ec9bbc was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 11.5 KB
Line 
1/**
2 * @file
3 *
4 * @brief RTEMS File Systems Link Routines
5 * @ingroup rtems_rfs
6 *
7 * These functions manage links. A link is the addition of a directory entry
8 * in a parent directory and incrementing the links count in the inode.
9 */
10
11/*
12 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <inttypes.h>
24#include <string.h>
25
26#include <rtems/rfs/rtems-rfs-block.h>
27#include <rtems/rfs/rtems-rfs-buffer.h>
28#include <rtems/rfs/rtems-rfs-file-system.h>
29#include <rtems/rfs/rtems-rfs-trace.h>
30#include <rtems/rfs/rtems-rfs-dir.h>
31#include <rtems/rfs/rtems-rfs-dir-hash.h>
32#include <rtems/rfs/rtems-rfs-link.h>
33
34int
35rtems_rfs_link (rtems_rfs_file_system* fs,
36                const char*            name,
37                int                    length,
38                rtems_rfs_ino          parent,
39                rtems_rfs_ino          target,
40                bool                   link_dir)
41{
42  rtems_rfs_inode_handle parent_inode;
43  rtems_rfs_inode_handle target_inode;
44  uint16_t               links;
45  int                    rc;
46
47  if (rtems_rfs_trace (RTEMS_RFS_TRACE_LINK))
48  {
49    int c;
50    printf ("rtems-rfs: link: parent(%" PRIu32 ") -> ", parent);
51    for (c = 0; c < length; c++)
52      printf ("%c", name[c]);
53    printf ("(%" PRIu32 ")\n", target);
54  }
55
56  rc = rtems_rfs_inode_open (fs, target, &target_inode, true);
57  if (rc)
58    return rc;
59
60  /*
61   * If the target inode is a directory and we cannot link directories
62   * return a not supported error code.
63   */
64  if (!link_dir && S_ISDIR (rtems_rfs_inode_get_mode (&target_inode)))
65  {
66    rtems_rfs_inode_close (fs, &target_inode);
67    return ENOTSUP;
68  }
69
70  rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
71  if (rc)
72  {
73    rtems_rfs_inode_close (fs, &target_inode);
74    return rc;
75  }
76
77  rc = rtems_rfs_dir_add_entry (fs, &parent_inode, name, length, target);
78  if (rc > 0)
79  {
80    rtems_rfs_inode_close (fs, &parent_inode);
81    rtems_rfs_inode_close (fs, &target_inode);
82    return rc;
83  }
84
85  links = rtems_rfs_inode_get_links (&target_inode) + 1;
86  rtems_rfs_inode_set_links (&target_inode, links);
87
88  rc = rtems_rfs_inode_time_stamp_now (&parent_inode, true, true);
89  if (rc > 0)
90  {
91    rtems_rfs_inode_close (fs, &parent_inode);
92    rtems_rfs_inode_close (fs, &target_inode);
93    return rc;
94  }
95
96  rc = rtems_rfs_inode_close (fs, &parent_inode);
97  if (rc > 0)
98  {
99    rtems_rfs_inode_close (fs, &target_inode);
100    return rc;
101  }
102
103  rc = rtems_rfs_inode_close (fs, &target_inode);
104
105  return rc;
106}
107
108int
109rtems_rfs_unlink (rtems_rfs_file_system* fs,
110                  rtems_rfs_ino          parent,
111                  rtems_rfs_ino          target,
112                  uint32_t               doff,
113                  rtems_rfs_unlink_dir   dir_mode)
114{
115  rtems_rfs_inode_handle parent_inode;
116  rtems_rfs_inode_handle target_inode;
117  uint16_t               links;
118  bool                   dir;
119  int                    rc;
120
121  if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
122    printf ("rtems-rfs: unlink: parent(%" PRIu32 ") -X-> (%" PRIu32 ")\n", parent, target);
123
124  rc = rtems_rfs_inode_open (fs, target, &target_inode, true);
125  if (rc)
126    return rc;
127
128  /*
129   * If a directory process the unlink mode.
130   */
131
132  dir = RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&target_inode));
133  if (dir)
134  {
135    switch (dir_mode)
136    {
137      case rtems_rfs_unlink_dir_denied:
138        if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
139          printf ("rtems-rfs: link is a directory\n");
140        rtems_rfs_inode_close (fs, &target_inode);
141        return EISDIR;
142
143      case rtems_rfs_unlink_dir_if_empty:
144        rc = rtems_rfs_dir_empty (fs, &target_inode);
145        if (rc > 0)
146        {
147          if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
148            printf ("rtems-rfs: dir-empty: %d: %s\n", rc, strerror (rc));
149          rtems_rfs_inode_close (fs, &target_inode);
150          return rc;
151        }
152        break;
153
154      default:
155        break;
156    }
157  }
158
159  rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
160  if (rc)
161  {
162    if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
163      printf ("rtems-rfs: link: inode-open failed: %d: %s\n",
164              rc, strerror (rc));
165    rtems_rfs_inode_close (fs, &target_inode);
166    return rc;
167  }
168
169  rc = rtems_rfs_dir_del_entry (fs, &parent_inode, target, doff);
170  if (rc > 0)
171  {
172    if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
173      printf ("rtems-rfs: unlink: dir-del failed: %d: %s\n",
174              rc, strerror (rc));
175    rtems_rfs_inode_close (fs, &parent_inode);
176    rtems_rfs_inode_close (fs, &target_inode);
177    return rc;
178  }
179
180  links = rtems_rfs_inode_get_links (&target_inode);
181
182  if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
183    printf ("rtems-rfs: unlink: target:%" PRIu32 " links:%u\n", target, links);
184
185  if (links > 1)
186  {
187    links--;
188    rtems_rfs_inode_set_links (&target_inode, links);
189  }
190  else
191  {
192    /*
193     * Erasing the inode releases all blocks attached to it.
194     */
195    rc = rtems_rfs_inode_delete (fs, &target_inode);
196    if (rc > 0)
197    {
198      if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
199        printf ("rtems-rfs: unlink: inode-del failed: %d: %s\n",
200                rc, strerror (rc));
201      rtems_rfs_inode_close (fs, &parent_inode);
202      rtems_rfs_inode_close (fs, &target_inode);
203      return rc;
204    }
205
206    if (dir)
207    {
208      links = rtems_rfs_inode_get_links (&parent_inode);
209      if (links > 1)
210        links--;
211      rtems_rfs_inode_set_links (&parent_inode, links);
212    }
213  }
214
215  rc = rtems_rfs_inode_time_stamp_now (&parent_inode, true, true);
216  if (rc > 0)
217  {
218    if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
219      printf ("rtems-rfs: link: inode-time-stamp failed: %d: %s\n",
220              rc, strerror (rc));
221    rtems_rfs_inode_close (fs, &parent_inode);
222    rtems_rfs_inode_close (fs, &target_inode);
223    return rc;
224  }
225
226  rc = rtems_rfs_inode_close (fs, &parent_inode);
227  if (rc > 0)
228  {
229    if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
230      printf ("rtems-rfs: link: parent inode-close failed: %d: %s\n",
231              rc, strerror (rc));
232    rtems_rfs_inode_close (fs, &target_inode);
233    return rc;
234  }
235
236  rc = rtems_rfs_inode_close (fs, &target_inode);
237
238  if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
239    printf ("rtems-rfs: link: target inode-close failed: %d: %s\n",
240            rc, strerror (rc));
241
242  return rc;
243}
244
245int
246rtems_rfs_symlink (rtems_rfs_file_system* fs,
247                   const char*            name,
248                   int                    length,
249                   const char*            link,
250                   int                    link_length,
251                   uid_t                  uid,
252                   gid_t                  gid,
253                   rtems_rfs_ino          parent)
254{
255  rtems_rfs_inode_handle inode;
256  rtems_rfs_ino          ino;
257  int                    rc;
258
259  if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK))
260  {
261    int c;
262    printf ("rtems-rfs: symlink: parent:%" PRIu32 " name:", parent);
263    for (c = 0; c < length; c++)
264      printf ("%c", name[c]);
265    printf (" link:");
266    for (c = 0; c < link_length; c++)
267      printf ("%c", link[c]);
268  }
269
270  if (link_length >= rtems_rfs_fs_block_size (fs))
271    return ENAMETOOLONG;
272
273  rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
274                               RTEMS_RFS_S_SYMLINK,
275                               1, uid, gid, &ino);
276  if (rc > 0)
277    return rc;
278
279  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
280  if (rc > 0)
281    return rc;
282
283  /*
284   * If the link length is less than the length of data union in the inode
285   * place the link into the data area else allocate a block and write the link
286   * to that.
287   */
288  if (link_length < RTEMS_RFS_INODE_DATA_NAME_SIZE)
289  {
290    memset (inode.node->data.name, 0, RTEMS_RFS_INODE_DATA_NAME_SIZE);
291    memcpy (inode.node->data.name, link, link_length);
292    rtems_rfs_inode_set_block_count (&inode, 0);
293  }
294  else
295  {
296    rtems_rfs_block_map     map;
297    rtems_rfs_block_no      block;
298    rtems_rfs_buffer_handle buffer;
299    uint8_t*                data;
300
301    rc = rtems_rfs_block_map_open (fs, &inode, &map);
302    if (rc > 0)
303    {
304      rtems_rfs_inode_close (fs, &inode);
305      return rc;
306    }
307
308    rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
309    if (rc > 0)
310    {
311      rtems_rfs_block_map_close (fs, &map);
312      rtems_rfs_inode_close (fs, &inode);
313      return rc;
314    }
315
316    rc = rtems_rfs_buffer_handle_open (fs, &buffer);
317    if (rc > 0)
318    {
319      rtems_rfs_block_map_close (fs, &map);
320      rtems_rfs_inode_close (fs, &inode);
321      return rc;
322    }
323
324    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
325    if (rc > 0)
326    {
327      rtems_rfs_block_map_close (fs, &map);
328      rtems_rfs_inode_close (fs, &inode);
329      return rc;
330    }
331
332    data = rtems_rfs_buffer_data (&buffer);
333
334    memset (data, 0xff, rtems_rfs_fs_block_size (fs));
335    memcpy (data, link, link_length);
336
337    rc = rtems_rfs_buffer_handle_close (fs, &buffer);
338    if (rc > 0)
339    {
340      rtems_rfs_block_map_close (fs, &map);
341      rtems_rfs_inode_close (fs, &inode);
342      return rc;
343    }
344
345    rc = rtems_rfs_block_map_close (fs, &map);
346    if (rc > 0)
347    {
348      rtems_rfs_inode_close (fs, &inode);
349      return rc;
350    }
351  }
352
353  rtems_rfs_inode_set_block_offset (&inode, link_length);
354
355  rc = rtems_rfs_inode_close (fs, &inode);
356
357  return rc;
358}
359
360int
361rtems_rfs_symlink_read (rtems_rfs_file_system* fs,
362                        rtems_rfs_ino          link,
363                        char*                  path,
364                        size_t                 size,
365                        size_t*                length)
366{
367  rtems_rfs_inode_handle inode;
368  int                    rc;
369
370  if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK_READ))
371    printf ("rtems-rfs: symlink-read: link:%" PRIu32 "\n", link);
372
373  rc = rtems_rfs_inode_open (fs, link, &inode, true);
374  if (rc)
375    return rc;
376
377  if (!RTEMS_RFS_S_ISLNK (rtems_rfs_inode_get_mode (&inode)))
378  {
379    rtems_rfs_inode_close (fs, &inode);
380    return EINVAL;
381  }
382
383  *length = rtems_rfs_inode_get_block_offset (&inode);
384
385  if (size < *length)
386  {
387    *length = size;
388  }
389
390  if (rtems_rfs_inode_get_block_count (&inode) == 0)
391  {
392    memcpy (path, inode.node->data.name, *length);
393  }
394  else
395  {
396    rtems_rfs_block_map     map;
397    rtems_rfs_block_no      block;
398    rtems_rfs_buffer_handle buffer;
399    char*                   data;
400
401    rc = rtems_rfs_block_map_open (fs, &inode, &map);
402    if (rc > 0)
403    {
404      rtems_rfs_inode_close (fs, &inode);
405      return rc;
406    }
407
408    rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
409    if (rc > 0)
410    {
411      rtems_rfs_block_map_close (fs, &map);
412      rtems_rfs_inode_close (fs, &inode);
413      return rc;
414    }
415
416    rc = rtems_rfs_buffer_handle_open (fs, &buffer);
417    if (rc > 0)
418    {
419      rtems_rfs_block_map_close (fs, &map);
420      rtems_rfs_inode_close (fs, &inode);
421      return rc;
422    }
423
424    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
425    if (rc > 0)
426    {
427      rtems_rfs_block_map_close (fs, &map);
428      rtems_rfs_inode_close (fs, &inode);
429      return rc;
430    }
431
432    data = rtems_rfs_buffer_data (&buffer);
433    memcpy (path, data, *length);
434
435    rc = rtems_rfs_buffer_handle_close (fs, &buffer);
436    if (rc > 0)
437    {
438      rtems_rfs_block_map_close (fs, &map);
439      rtems_rfs_inode_close (fs, &inode);
440      return rc;
441    }
442
443    rc = rtems_rfs_block_map_close (fs, &map);
444    if (rc > 0)
445    {
446      rtems_rfs_inode_close (fs, &inode);
447      return rc;
448    }
449  }
450
451  rc = rtems_rfs_inode_close (fs, &inode);
452
453  return rc;
454}
Note: See TracBrowser for help on using the repository browser.