[NTLUG:Discuss] Is there a way to change permissions of a link

Steve Baker sjbaker1 at airmail.net
Wed Nov 1 17:13:30 CST 2000


Kyle_Davenport at compusa.com wrote:
> 
> EMI: links in unix are not like the silly shortcuts in windows.  A soft link is
> simply a pointer in its directory's inode table to the target inode.  A hard
> link is actually the same file and inode by another name.  Many file commands
> like cp, mv, tar, find... have arguments that change how they treat links
> (whether they dereference them or not)

That's not correct....<sigh>...I guess I'd better give the FULL version of the
explanation...although it's enough to fill an hour of explanation if you do it
properly.

It's easiest to see how you are wrong by looking at how EARLY implementations
of UNIX handled symbolic links and hard links. (Linux and modern UNIXen are
a little different - but not in any way that matters).

In *early* UNIX, a file consisted of a big block of data and an "Information
Node" (inode for short).  The inode contained things like the location of
the data block on the disk, the length of the file, it's permissions, ownerships,
etc.  BUT THE INODE DOES NOT CONTAIN THE NAME OF THE FILE.

A directory was simply a completely ordinary file (with a bit in it's inode 'permission'
field to say that it's a directory).  It contained some number of 16 byte records each
containing a 14 byte filename and a two byte inode number...one for each file in the
directory.  That was in the bad old days when filenames had at most 14 characters and
there could be no more than 65536 files on any particular disk drive.

In a sense, the directory was just like a phone book - it's a way to associate
a handy name with the 'inode number' of the actual file.

In early UNIX, you could rename a file by editing the directory using 'vi'.  I've
actually done that. (You can't do that anymore - but that's beside the point).

Back then, all that a *HARD* link was - was two directory entries that happened to
point to the exact same inode.

Since the file's name was not in the inode (it still isn't), there wasn't (and still isn't)
any concept of which "place" in the file system the original file is - and which is the
link.  For hard links there is utter equality between all directory entries that happen
to point to the same inode.

Now, hard links are inconvenient and even dangerous for lots of reasons...so in later
versions of UNIX (and now in Linux) we gained "Symbolic" links.  In the original
implementation, all a symlink was was a completely normal file whose contents was
the pathname of another file.  A flag in the inode of the symlink "file" told the
filing system to go and do that level of indirection.

In modern UNIXen (and Linux) the directory is more complex than it was in the
olden days - but the principle is the same.  UNIX really has a 'flat' filing
system - with each file having a simple number to identify it.  The illusion
of our fancy heirarchical directory system with all it's human readable filenames
is a layer built on top of the basic 'inode + data' scheme.  There is also a lot
more complexity in the inode structure - very long files have inodes that point
to more inodes and stuff like that...but for the purposes of understanding how
links work, the old mechanism makes the whole thing much more comprehensible.

So, a 'soft' link DOES NOT POINT TO THE INODE of the actual data file, it points
to the NAME of the data file.

Try this:

 % echo "Hello World" > A
 % ln -s A B
 % cat B
 Hello World
 % mv A C
 % cat B
 cat: B: No such file or directory
 %

Notice that although we renamed A to C, we didn't change it's inode number. The "mv"
command doesn't touch the file itself - or it's inode, it only changes the directory
entry that points to that inode.  Since 'B' only contains the *NAME* of the file 'A',
when we rename A, B can't find it anymore and it's a 'dead' link that points nowhere.

Now do the same experiment with a hard link:

 % rm B C
 % echo "Hello World" > A
 % ln A B
 % cat B
 Hello World
 % mv A C
 % cat B
 Hello World
 %

In this case, B points to the *inode* of A - and subsequent changes to the name
of A don't affect the inode - so B *still* points to it.

In fact, if it's a hard link, you can even:

 % rm C
 % cat B
 Hello World
 %

...because C and B are simply links to the same file.

This explains why the UNIX system call to "delete" a file is called 'unlink'
because it DOESN'T actually delete the file at all. All it does is to unlink
it's directory entry from the inode - and let's UNIX's garbage collection
get rid of the file if that happens to be the last link to it.

The 'rm' shell command is really a mis-nomer because it doesn't unlink a file
at all.

A couple of other interesting things:  The inode contains a count of the
number of hard-links to the file (UNIX/Linux needs that so that the
garbage collecter can erase the file and recycle it's inode when there
are no links to it anymore)...when you do an 'ls -l', the link counter is
listed in the second column.  Notice that it's nearly always '1' for regular
files - but for directories, it's always larger?  That's because every
directory has a "file" called "." inside that is in fact a hard-link back
to itself...and if that directory contains subdirectories then each one
will have a "file" called ".." which is a hard link to it's parent.

In fact, looking at the link count for a directory and subtracting two
from that number will *generally* tell you how many subdirectories it
has.

Another thing you can do is 'ls -i'...this lists the actual 'inode' numbers
for each file.

  % echo "Hello World" > X
  % ln X Y
  % ls -li
  total 2
  4884523 -rw-rw-rw-   2 steve    users          12 Nov  1 16:55 X
  4884523 -rw-rw-rw-   2 steve    users          12 Nov  1 16:55 Y
  ^^^^                 ^                         ^^
  inode            link count               length of "Hello World\n"

Notice how they have identical inode numbers (and notice how modern UNIXen
allow more than 65536 files!)

Now do:

  % ln -s X Z
  % ls -li
  4884523 -rw-rw-rw-   2 steve    users          12 Nov  1 16:55 X
  4884523 -rw-rw-rw-   2 steve    users          12 Nov  1 16:55 Y
  4884524 lrwxrwxrwx   1 steve    users           1 Nov  1 17:06 Z -> X

Notice that Z has it's own inode - with a link count of only 1 and is
only one byte long...that's the length of the string 'X'.  If you look
at the length of a symbolic link to a file with a LONG filename, you'll
see that the length of the link "file" is always the same as the length
of the file it links to.

I hope this makes things clearer.

-- 
Steve Baker   HomeEmail: <sjbaker1 at airmail.net>
              WorkEmail: <sjbaker at link.com>
              HomePage : http://web2.airmail.net/sjbaker1
              Projects : http://plib.sourceforge.net
                         http://tuxaqfh.sourceforge.net
                         http://tuxkart.sourceforge.net
                         http://prettypoly.sourceforge.net




More information about the Discuss mailing list