Bug? in os.chown()

Jim Dennis jimd at vega.starshine.org
Mon Jan 1 19:21:08 EST 2001


In article <92q08p$1doj$1 at news.cybercity.dk>, Erwin S. Andreasen wrote:

>On Sun, 31 Dec 2000 17:27:25 -0600, David Lambert wrote:
>> I am running Python 2.0 on Mandrake Linux 7.2 and have come across an
>> apparent anomaly with os.chown(). Running a process as root, I can
>> change any file's ownerships apart from symbolic links. No error is
>> given, but the ownership refuses to be changed. Is this a feature or a
>> bug? How do I change a symbolic link's owner and group?

> Just about any operation on a symbolic link (i.e. open, chdir etc. but not
> unlink) will act on the file linked to instead. So you are really changing the
> permission on the target file. (Note, however, that while the system call
> chown follows the link, the GNU chown program does NOT follow the link and
> changes the owner of the link -- at least with 4.0.35 version of fileutils).

> There are a number of l* system calls that act on the link rather than the
> thing being linked to (lstat, lchown). However, Python doesn't implement
> lchown yet (at least not in Python 2.0b1).

> So, I suppose you could use system() to run GNU chown on the file (you could
> give it the --no-dereference flag to be sure, see man 1 chown) -- it's only
> necessary to do it when the target is a symbolic link (you can check using
> os.path.islink). Not a very portable solution though.

 Looking at my O'Reilly/Lutz Pocket Reference I see that there is a
 readlink() method somewhere under the os module.  It wasn't clear
 whether they meant os.readlink() or os.path.readlink() (from the 
 text of the book).  I've figured out that os.readlink() works.

 It appears that os.readlink() only follows one level of linkage.

  (I tested this by preparing a simple set of symlinks using:
  	cd tmp && touch foo && ln -s foo lfoo; ln -s lfoo llfoo
	ln -s llfoo lllfoo 
   and then interactively importing os and playing with it; duh).

 So I guess you need to do something like:

 	fname="./lllfoo"
	while os.path.islink(fname):
		fname=os.readlink(fname)

 (which works for my test case, though I notice that it 
 stripped the leading ./ from my name;  I guess it does some
 sort of path canonicalization).

 ... is there a better way?  Is there a "readlinks()" method
 that automates this process?  Does this throw an exception
 if the link is dangling, or if it is circular, or if it
 "might" be circular because it exceeds some maximum?  Should
 I wrap os.readlink() in a try: except:?  What are the exceptions
 that os.readlink() can throw?  What are the exceptions that 
 os.path.islink() could throw?  (ENOENT, and EPERM seem like
 obvious OS errors; but I know know how to find the Python 
 exception names that correspond to these system errors).




More information about the Python-list mailing list