[gnu.utils.bug] ld: Problem when overwriting an existing output file

schoenfr%tubsibr@UUNET.UU.NET (Erik Schoenfelder) (12/14/89)

Hi!

About: Problem creating the output file, if it exists and is owned by
someone other, but write permission is given for the file and directory.


System :
	Sun 3/60 SunOS 4.0.3_EXPORT

Version of ld.c (from binutils.tar.Z) :
	-rw-rw-rw- 5381/11 128917 Oct 17 17:50 1989 binutils/ld.c


Working on a project, with group permission for the members, we had
the following problem:
Ld generates a new output-file, but aborts with 
	`ld: Not owner for a.out', 
if the output file exists and is owned by someone other.


For example :  (user `neitzel' and `schoenfr' are members of group `staff')

% ls -dgl .
drwxrwxr-x  2 neitzel  staff         512 Dec 12 18:22 .
% ls -lg a.out
-rwxrwxr-x  1 neitzel  staff       36301 Dec 12 18:22 a.out
% whoami
schoenfr
% gcc -v foo.o
gcc version 1.36
 /usr/local/lib/gcc-ld -e start -dc -dp /lib/crt0.o /lib/Mcrt1.o foo.o /usr/local/lib/gcc-gnulib -lc
ld: Not owner for a.out
% ls -lg a.out
-rwxrwxr-x  1 neitzel  staff       36301 Dec 12 18:23 a.out
% 

The problem is the `chmod()' call when setting the execute
permission not being the owner.

ld.c>	  close (outdesc);
ld.c>	
ld.c>	  if (chmod (output_filename, filemode | 0111) == -1)
ld.c>	    perror_name (output_filename);
ld.c>	}

Clearing the permission fails too, but is not checked.


Solutions :

	(1) Ignore the return value of chmod().
	 -> Bad; it is possible, that the `x' permission is not set.

	(2) Linking is done to a temprary file, and this is mv'd to the
	    output-file (if this is a plain file).
	 -> Good; an existing file is not destroyed if no new
	    executable can be created.
	    (i think our sun does this)

	(3) Unlink an existing output-file.
	 -> Hmm; if the existing output-file is a plain file, this
	    seems to be a useable solution (and somehow simple to
	    implement). 


A fix for solution (3) would be:


*** ld.c.original	Tue Dec 12 16:55:39 1989
--- ld.c	Wed Dec 13 04:39:22 1989
***************
*** 3274,3279 ****
--- 3274,3284 ----
    struct stat statbuf;
    int filemode;
  
+   if (stat (output_filename, &statbuf) >= 0
+       && (statbuf.st_mode & S_IFMT) == S_IFREG
+       && unlink (output_filename) < 0)
+     perror_name (output_filename);
+ 
    outdesc = open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (outdesc < 0) perror_name (output_filename);


If the file exists, and it is a plain file, then it is removed. If it
cannot be removed, this is reported as an error.

I hope this helps.

-- Erik