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