+/**
+ * Construct a link from parent/name to target.
+ */
+static int ryfs_symlink(const rtems_filesystem_location_info_t *parent_loc,
+ const char *name,
+ size_t namelen,
+ const char *target)
+{
+ struct yaffs_obj *parent_dir = ryfs_get_object_by_location(parent_loc);
+ struct yaffs_dev *dev = parent_dir->my_dev;
+ uint32_t mode;
+ struct yaffs_obj *created_link;
+ int ret;
+
+ ylock(dev);
+
+ mode = S_IFLNK |
+ ((S_IRWXU | S_IRWXG | S_IRWXO) & ~rtems_filesystem_umask);
+
+ created_link = yaffs_create_symlink(parent_dir, name, mode,
+ geteuid(), getegid(), target);
+
+ if (created_link != NULL) {
+ // In RTEMS VFS, there is no filesytem-wide sync(), only per-file
+ // flushes. Filesystem-wide sync is implemented by looping over all of
+ // the open files and individually fsync()ing them. That's part of why
+ // every close() in RTEMS-yaffs is accompanied by an implicit fsync().
+ // There is no such close() call associated with the symlink's creation,
+ // since it wasn't created via open(). Therefore, flush it immediately
+ // instead.
+ yaffs_flush_file(created_link, 0, 0, 0);
+ ret = 0;
+ } else {
+ errno = EINVAL;
+ ret = -1;
+ }
+
+ yunlock(dev);
+ return ret;
+}
+
+/**
+ * Read the target name of a symbolic link. Interpretation of the path name is
+ * up to the caller.
+ *
+ * @param loc The location of the symlink
+ * @param dst_buf A non-NULL pointer to the caller's buffer for the characters.
+ * @param dst_buf_size The size of the caller's buffer in characters.
+ *
+ * @retval -1 An error occurred, the error may be found via errno.
+ * @retval non-negative size of the actual contents in characters, including the
+ * terminating NULL.
+ */
+static ssize_t ryfs_readlink(const rtems_filesystem_location_info_t *loc,
+ char *dst_buf, size_t dst_buf_size)
+{
+ struct yaffs_obj *link = ryfs_get_object_by_location(loc);
+ struct yaffs_dev *dev = link->my_dev;
+
+ ylock(dev);
+ ssize_t chars_copied = -1;
+
+ link = yaffs_get_equivalent_obj(link);
+ if (!link) {
+ errno = EBADF;
+ goto error_locked;
+ }
+
+ if (link->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) {
+ errno = EINVAL;
+ goto error_locked;
+ }
+
+ // Source string length including the terminating NULL.
+ size_t src_buf_size = strlen(link->variant.symlink_variant.alias) + 1;
+ if (src_buf_size > dst_buf_size)
+ src_buf_size = dst_buf_size;
+ memcpy(dst_buf, link->variant.symlink_variant.alias, src_buf_size);
+ chars_copied = src_buf_size;
+
+error_locked:
+ yunlock(dev);
+ return chars_copied;
+}
+