io_link()

hi:

i am writing the io_link() handler for a resource manager. as per the
documentation, it’s supposed to be exactly like io_rename(); i.e.i get
the name of the newpath in the ‘msg’ structure and the name of the
oldpath in ‘extra’ structure; so i have both thee to work with.

but for some reason ‘extra’ seems to have junk…
i looked at the client-side code for link(and symlink) and rename, and
it looks like they’re different.

help would be greatly appreciated.

thanks,
rommel

Rommel Dongre <rdongre@pillardata.com> wrote:

i am writing the io_link() handler for a resource manager. as per the
documentation, it’s supposed to be exactly like io_rename(); i.e.i get
the name of the newpath in the ‘msg’ structure and the name of the
oldpath in ‘extra’ structure; so i have both thee to work with.

What documentation did you read that in, because it is wrong!? The
IO_LINK is not like an IO_RENAME. Um, unless you’re talking about
symbolic links, which do have two path names; a hard link is a path
name and an open fd/ocb (to the existing original, which will have
been opened via an ordinary open()/connect message first by libc).
So to suport hard links your “filesystem” should internally properly
differentiate between file objects and name links (a file/inode may
have multiple independant names/links and a file/inode may be open
by multiple clients/fds … a many-to-one-to-many relationship).

i looked at the client-side code for link(and symlink) and rename, and
it looks like they’re different.

For link:
“extra->ocb” names the existing file (this ocb was previously set up
by libc through a call into your open() handler); the name to give the
new link is held in “msg->connect.path”/“msg->connect.path_len”

For symlink:
“msg->connect.path”/“msg->connect.path_len” names the new symlink
to be created; it will point to “extra->path”/“msg->connect.extra_len”
as its target

For rename:
“extra->path”/“msg->connect.extra_len” names the existing file; it is
to be renamed as “msg->connect.path”/“msg->connect.path_len”

rename() has its own callout; link/symlink share a callout and you use
the “msg->connect.extra_type” to differentiate the two cases, and hence
know how to interpret the “extra” message data union (extra->ocb or
extra->path respectively).

Rommel Dongre <rdongre@pillardata.com> wrote:

hi:

i am writing the io_link() handler for a resource manager. as per the
documentation, it’s supposed to be exactly like io_rename(); i.e.i get
the name of the newpath in the ‘msg’ structure and the name of the
oldpath in ‘extra’ structure; so i have both thee to work with.

but for some reason ‘extra’ seems to have junk…
i looked at the client-side code for link(and symlink) and rename, and
it looks like they’re different.

help would be greatly appreciated.

Looking at the source for link, it calls open on the old path, then
flink() with the new path in the message structure.

So, I’d say you have to the attribute structure that the current OCB
points to to determine the oldpath, and that the message will have
the newpath.

The extra seems to be of type

io_link_extra_t, and appears to have ConnectServerInfo() about
the server that owns the fd, and client information – client
pid, client fd, etc.

Contrarily, symlink() does an open on the symlink pathname for
create, and includes the path name it should point to as a second
part of the message.

So:
link() - OCB->attr is the existing file, pathname in message is new
path to create
symlink() - OCB->attr is the new symlink entry, pathname in message
is where this symlink should point
rename() - handled in io_open(), both paths are in the message, no OCB

Used cvs.qnx.com to look at the three client side, and a bit of figuring
to get this.

If our docs don’t match the above, they probably need to be updated/enhanced.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs wrote:

If our docs don’t match the above, they probably need to be updated/enhanced.

Ahhh, since someone brought the subject up :slight_smile:

I have no problem creating a hard link, but I am having trouble with
creating a symbolic link.

When I get a symbolic link request (from ln -s) the path that represents
the target (the file being linked to) is relative to the current working
directory for ln. How am I supposed to resolve this path in the
resource manager ? (if I manually type the path to ln, as I would get it
during an open - i.e. relative to my mount - my symlink handler works fine).

Rennie

Rennie Allen <rgallen@attbi.com> wrote:

I have no problem creating a hard link, but I am having trouble with
creating a symbolic link.
When I get a symbolic link request (from ln -s) the path that represents
the target (the file being linked to) is relative to the current working
directory for ln. How am I supposed to resolve this path in the
resource manager ? (if I manually type the path to ln, as I would get it
during an open - i.e. relative to my mount - my symlink handler works fine).

You don’t. You shouldn’t care about what the link actually points to;
in particular you shouldn’t attempt to resolve it at that point, it
doesn’t have to be a valid pathname or indicate an existing file. The
only time you need to attempt resolution is during a connect message
(such as open()) and you encounter the symlink, at which point you do
the string operations to make the new pathname and redirect/bounce it.

Rennie Allen <rgallen@attbi.com> wrote:

David Gibbs wrote:

If our docs don’t match the above, they probably need to be updated/enhanced.

Ahhh, since someone brought the subject up > :slight_smile:

I have no problem creating a hard link, but I am having trouble with
creating a symbolic link.

When I get a symbolic link request (from ln -s) the path that represents
the target (the file being linked to) is relative to the current working
directory for ln. How am I supposed to resolve this path in the
resource manager ? (if I manually type the path to ln, as I would get it
during an open - i.e. relative to my mount - my symlink handler works fine).

How are you specifying your “ln -s” command line? Are you giving it an
absolute or relative path?

If giving it a relative path, all you store away is the relative path.

Try this:

cd /tmp
mkdir ttt
cd ttt
mkdir aaa
mkdir bbb
cd bbb
touch file
ln -s file …/aaa/link
cd …/aaa
cat link

You will get “no such file or directory”.
Try “ls -l link” and it will contain say “link → a”

Symbolic links are dumb – they are very much “caveat linkor”.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Rennie Allen <rgallen@attbi.com> wrote:

John Garvey wrote:

You don’t. You shouldn’t care about what the link actually points to;
in particular you shouldn’t attempt to resolve it at that point, it
doesn’t have to be a valid pathname or indicate an existing file. The
only time you need to attempt resolution is during a connect message
(such as open()) and you encounter the symlink, at which point you do
the string operations to make the new pathname and redirect/bounce it.

Ahhh, OK. That clears things up. I just got to the symlink handler and
was (mindlessly) applying the same checking that I did for all the other
handlers (with no need).

Here’s a work-in-progress “pathwalk()” function that converts the
filename into a series of attributes structures – this is from the
“new and as-yet-unreleased” version of the ramdisk… It currently
bounces the symlink request to a higher level…

Is this correct in as far as this function goes?

int
pathwalk (resmgr_context_t *ctp, char *pathname, cfs_attr_t *mountpoint, int flags, cfs_attr_t **output, int *nrets)
{
int nels;
int sts;
char fname [_POSIX_PATH_MAX];
char *p;
struct _client_info cinfo;

nels = countchars (pathname, ‘/’) + 1; // +1 'cuz the leading “/” is already stripped…
if (nels > *nrets) {
return (E2BIG);
}

if ((sts = iofunc_client_info (ctp, 0, &cinfo)) != EOK) { // 0 == flags, O_REALIDS as a QNX 6 extension; @@@ think hard @@@
return (sts);
}

strcpy (fname, pathname); // make copy, 'cuz strtok buggers it up

output [*nrets = 0] = mountpoint; // a given; we always start at the mountpoint
++*nrets;

for (p = strtok (fname, “/”); p; p = strtok (NULL, “/”)) {

/*

  • in order to be able to process another pathname component (“p” in
  • this case), the previous pathname component (*nrets - 1) must be
  • a directory, and …
    */

if (!S_ISDIR (output [*nrets - 1] → attr.mode)) {
return (ENOTDIR);
}

/*

  • … we must have access permissions.
    */

if ((sts = iofunc_check_access (ctp, &output [*nrets - 1] → attr, S_IEXEC, &cinfo)) != EOK) {
return (sts);
}

/*

  • At this point we have the ability to do a directory seek.
  • If we can find the entry, then …
    */

if (!(output [*nrets] = search_dir (p, output [*nrets - 1]))) {
return (ENOENT);
}

/*

  • … we can bump our “found” count and …
    */

++*nrets;

/*

  • … process the entry itself.
  • We check to see if it’s a symbolic link, and abort if it is.
  • (Symbolic links are handled higher up).
    */

if (S_ISLNK (output [*nrets - 1] → attr.mode)) {
return (EOK);
}
}

return (EOK);
}

Robert Krten, PARSE Software Devices +1 613 599 8316.
Realtime Systems Architecture, Books, Video-based and Instructor-led
Training and Consulting at www.parse.com.
Email my initials at parse dot com.

John Garvey wrote:

You don’t. You shouldn’t care about what the link actually points to;
in particular you shouldn’t attempt to resolve it at that point, it
doesn’t have to be a valid pathname or indicate an existing file. The
only time you need to attempt resolution is during a connect message
(such as open()) and you encounter the symlink, at which point you do
the string operations to make the new pathname and redirect/bounce it.

Ahhh, OK. That clears things up. I just got to the symlink handler and
was (mindlessly) applying the same checking that I did for all the other
handlers (with no need).

Thanks.

Rennie

Robert Krten <nospam83@parse.com> wrote:

Here’s a work-in-progress “pathwalk()” function that converts the

if (S_ISLNK (output [*nrets - 1] → attr.mode)) {

For a “real filesystem” you want to be more discriminating when
deciding whether or not to “follow” the link … consider the
different requirements of open() versus unlink() … the latter
is defined to operate on the symlink itself. You probably need
to pass in a flag from the higher-level resmgr/connect handler.

John Garvey <jgarvey@qnx.com> wrote:

Robert Krten <> nospam83@parse.com> > wrote:
Here’s a work-in-progress “pathwalk()” function that converts the

if (S_ISLNK (output [*nrets - 1] → attr.mode)) {

For a “real filesystem” you want to be more discriminating when
deciding whether or not to “follow” the link … consider the
different requirements of open() versus unlink() … the latter
is defined to operate on the symlink itself. You probably need
to pass in a flag from the higher-level resmgr/connect handler.

Thanks John, I’ll include that :slight_smile:

One other thing I thought of after posting it was that I should
probably have some kind of char * that gets returned indicating
where the last match failed – that way, when I go to create a
file/dir within a directory, I can tell if the last component is
present or not; currently, it just returns attributes structures
to indicate the number of matched components, but there’s no linkage
to the higher level to indicate how many should have been matched.

Cheers,
-RK


Robert Krten, PARSE Software Devices +1 613 599 8316.
Realtime Systems Architecture, Books, Video-based and Instructor-led
Training and Consulting at www.parse.com.
Email my initials at parse dot com.