~ubuntu-branches/ubuntu/precise/gzip/precise

« back to all changes in this revision

Viewing changes to lib/unlink.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-10-19 11:42:42 UTC
  • mfrom: (4.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20111019114242-d8wiiu8kbvdtgmgj
Tags: 1.4-1ubuntu1
* Merge with Debian testing.  Remaining Ubuntu changes:
  - debian/{control,rules}: Remove the Win32 build and mingw64
    build-dependency, since mingw is in universe, and will remain so for
    the forseeable future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Work around unlink bugs.
 
2
 
 
3
   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
 
4
 
 
5
   This program is free software: you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation; either version 3 of the License, or
 
8
   (at your option) any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
#include <config.h>
 
19
 
 
20
#include <unistd.h>
 
21
 
 
22
#include <errno.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <sys/stat.h>
 
26
 
 
27
#undef unlink
 
28
 
 
29
/* Remove file NAME.
 
30
   Return 0 if successful, -1 if not.  */
 
31
 
 
32
int
 
33
rpl_unlink (char const *name)
 
34
{
 
35
  /* Work around Solaris 9 bug where unlink("file/") succeeds.  */
 
36
  size_t len = strlen (name);
 
37
  int result = 0;
 
38
  if (len && ISSLASH (name[len - 1]))
 
39
    {
 
40
      /* We can't unlink(2) something if it doesn't exist.  If it does
 
41
         exist, then it resolved to a directory, due to the trailing
 
42
         slash, and POSIX requires that the unlink attempt to remove
 
43
         that directory (which would leave the symlink dangling).
 
44
         Unfortunately, Solaris 9 is one of the platforms where the
 
45
         root user can unlink directories, and we don't want to
 
46
         cripple this behavior on real directories, even if it is
 
47
         seldom needed (at any rate, it's nicer to let coreutils'
 
48
         unlink(1) give the correct errno for non-root users).  But we
 
49
         don't know whether name was an actual directory, or a symlink
 
50
         to a directory; and due to the bug of ignoring trailing
 
51
         slash, Solaris 9 would end up successfully unlinking the
 
52
         symlink instead of the directory.  Technically, we could use
 
53
         realpath to find the canonical directory name to attempt
 
54
         deletion on.  But that is a lot of work for a corner case; so
 
55
         we instead just use an lstat on the shortened name, and
 
56
         reject symlinks with trailing slashes.  The root user of
 
57
         unlink(1) will just have to live with the rule that they
 
58
         can't delete a directory via a symlink.  */
 
59
      struct stat st;
 
60
      result = lstat (name, &st);
 
61
      if (result == 0)
 
62
        {
 
63
          /* Trailing NUL will overwrite the trailing slash.  */
 
64
          char *short_name = malloc (len);
 
65
          if (!short_name)
 
66
            {
 
67
              errno = EPERM;
 
68
              return -1;
 
69
            }
 
70
          memcpy (short_name, name, len);
 
71
          while (len && ISSLASH (short_name[len - 1]))
 
72
            short_name[--len] = '\0';
 
73
          if (len && (lstat (short_name, &st) || S_ISLNK (st.st_mode)))
 
74
            {
 
75
              free (short_name);
 
76
              errno = EPERM;
 
77
              return -1;
 
78
            }
 
79
          free (short_name);
 
80
        }
 
81
    }
 
82
  if (!result)
 
83
    result = unlink (name);
 
84
  return result;
 
85
}