Page 1 of 1

How do I query information for a link?

PostPosted: Mon Aug 01, 2016 7:47 am
by colinward
Hello.

I have a C++ support class that can be used for querying directory contents on multiple platforms. You call it and it returns a list of objects with information about the files present in the directory. It is cross platform and works on Amiga OS, Linux and Windows. Each entry returned will be in a structure like the following:

struct TEntry
{
char *Name;
char *Link;
bool IsLink;
...
};

If a file is not a link then Name will point to its name, Link will be NULL and IsLink will be false.

If a file *is* a link then Name will point to the name of the source link, Link will point to the name of the file the link points to and IsLink will be true.

On Linux and Windows you can control whether a link is dereferenced or not when you query a file. On Linux, lstat() queries info about the link and stat() resolves the link and queries info about the file the link points to. On Windows you can control this behaviour passing the FILE_FLAG_OPEN_REPARSE_POINT to CreateFile().

On Amiga OS I cannot find any such mechanism. IDOS->ExamineObjectTags() always dereferences the link and does not fill out the Link member of the ExamineData structure. Ok, I could use IDOS->ExamineDir() to iterate through all entries in the directory but this is an ugly workaround and has performance implications.

Any ideas?

Re: How do I query information for a link?

PostPosted: Mon Aug 01, 2016 4:23 pm
by chris
apparently LockTagList() might help: http://www.amigans.net/modules/xforum/v ... e=0&mode=0

I don't know if we have access to that yet, I don't have the SDK to hand although I'm sure it has been updated since 2012.

Re: How do I query information for a link?

PostPosted: Mon Aug 01, 2016 6:14 pm
by xenic
colinward wrote:On Amiga OS I cannot find any such mechanism. IDOS->ExamineObjectTags() always dereferences the link and does not fill out the Link member of the ExamineData structure. Ok, I could use IDOS->ExamineDir() to iterate through all entries in the directory but this is an ugly workaround and has performance implications.

Here's some code I used last year to test LockTags():
Code: Select all
/* Compile: gcc -O2 checklinks.c -o checklinks -Wall -lauto */

#include <proto/exec.h>
#include <proto/dos.h>

struct RDArgs *argsdata;

enum
{
   ARG_PATH, ARG_MAX
};

int main(int argc, char **argv)
{
   uint32 imask = 0;
   BPTR lock = 0;
   STRPTR fpath = NULL;
   int32 args[ARG_MAX] = {0};

   if (argc == 0)
   {
      IDOS->PutErrStr("Error: Shell program\n");
      return(RETURN_ERROR);
   }

   argsdata = IDOS->ReadArgs("PATH/A", args, NULL);
   if (!argsdata)
   {
      IDOS->PrintFault(IDOS->IoErr(), "Error:");
      return(RETURN_ERROR);
   }

   fpath = (char *)args[ARG_PATH];
   lock = IDOS->LockTags(LK_Name, fpath, LK_InfoMask, &imask, TAG_DONE);
   if (lock)
   {
      if (imask & LOCKF_SOFTLINK_MIDPART)
      {
         IDOS->Printf("There is a link in the given path\n");
      }

      if (imask & LOCKF_SOFTLINK_ENDPART)
      {
         IDOS->Printf("The last component of the path is a link\n");
      }
      else
      {
         IDOS->Printf("The path contains NO links\n");
      }

      IDOS->UnLock(lock);
   }
   else
   {
      IDOS->PrintFault(IDOS->IoErr(), "Error:");
      IDOS->FreeArgs(argsdata);
      return(RETURN_ERROR);
   }

   IDOS->FreeArgs(argsdata);
   return(RETURN_OK);
}


When I read the autodoc I wasn't sure if the LOCKF_SOFTLINK_MIDPART and LOCKF_SOFTLINK_ENDPART flags were mutually exclusive. Apparently they are not.

Re: How do I query information for a link?

PostPosted: Tue Aug 02, 2016 1:49 am
by colinw
colinward wrote:Hello.
...
On Amiga OS I cannot find any such mechanism. IDOS->ExamineObjectTags() always dereferences the link
and does not fill out the Link member of the ExamineData structure.
Ok, I could use IDOS->ExamineDir() to iterate through all entries in the directory but this is an ugly workaround
and has performance implications.

Any ideas?

Yes...

Firstly, an operation on a link is equivalent to the same operation on the target object.

There are only three DOS functions that directly affect links themselves, those being;
IDOS->Delete(), IDOS->MakeLink() and conditionally IDOS->Rename().

The reason IDOS->ExamineObjectTags() returns information only on the target object of the link
is because the IDOS->Lock() function itself resolved the link when you called it, or called internally
when using the EX_StringInputName tag, so, you are getting information on what you asked for.

ExamineDir() returns information about links in a directlory because the reference lock was on
the parent directory, not on the link reference itself.

LockTags() is the only function that allows you to reliably differentiate a soft link name from a real object name.
Differentiating hardlinks is a little more complex because they are done inside the filesystem itself and are
transparent to the dos.library layer. (I have code to do this if you need it.)

Links are not "objects" in themselves, even if they may be treated as such inside a filesystem for
implementation purposes, outside of a filesystem context they are simply references to "real" objects
and as such, they have no auxilliary meta information other than target data and maybe a creation date.

There is no way to change meta-data on a link itself because all the IDOS->SetXXX() functions work
only on the target object.

Re: How do I query information for a link?

PostPosted: Thu Aug 04, 2016 4:53 am
by colinw
xenic wrote:Here's some code I used last year to test LockTags():
[...]
When I read the autodoc I wasn't sure if the LOCKF_SOFTLINK_MIDPART and LOCKF_SOFTLINK_ENDPART flags
were mutually exclusive. Apparently they are not.


You are correct, they are not, because you can have up to 15 softlinks in a path, eg: "vol:dirlink/filelink"
In this case both flags would be set.

You also have two additional tags to use with Locktags() for softlinks besides the lk_infomask, here's the autodoc;

LK_ResolveSL (int32) -- Optional switch to control automatic softlink
resolution, when this tag is set to FALSE, if the object
the LK_Name references is a softlink, this function will
return failure with IoErr() set to ERROR_IS_SOFT_LINK,
rather than performing the normal automatic resolution.
(Default; TRUE when tag is not specified) (Added 53.117)

LK_SoftLinks (uint32 *) -- Optional pointer to a storage area that is
the sizeof(uint32).
On success, the value pointed to, will contain the number
of softlinks resolved in the supplied path/name string.
0 will be returned when there are no softlinks.
(Currently 15 softlinks are the maximum for a path.)
(Default; NULL)

Re: How do I query information for a link?

PostPosted: Sat Aug 06, 2016 9:41 am
by tesla
Clib2 implements a couple of functions you might want to have a look at. I think the files stat_lock.c and unistd_readlink.c might be the most interesting to start with.