MCPcopy Create free account
hub / github.com/coreutils/coreutils / write_protected_non_symlink

Function write_protected_non_symlink

src/remove.c:95–160  ·  view source on GitHub ↗

Return 1 if FILE is an unwritable non-symlink, 0 if it is writable or some other type of file, -1 and set errno if there is some problem in determining the answer. Set *BUF to the file status. */

Source from the content-addressed store, hash-verified

93 -1 and set errno if there is some problem in determining the answer.
94 Set *BUF to the file status. */
95static int
96write_protected_non_symlink (int fd_cwd,
97 char const *file,
98 struct stat *buf)
99{
100 if (can_write_any_file ())
101 return 0;
102 if (cache_fstatat (fd_cwd, file, buf, AT_SYMLINK_NOFOLLOW) != 0)
103 return -1;
104 if (S_ISLNK (buf->st_mode))
105 return 0;
106 /* Here, we know FILE is not a symbolic link. */
107
108 /* In order to be reentrant -- i.e., to avoid changing the working
109 directory, and at the same time to be able to deal with alternate
110 access control mechanisms (ACLs, xattr-style attributes) and
111 arbitrarily deep trees -- we need a function like eaccessat, i.e.,
112 like Solaris' eaccess, but fd-relative, in the spirit of openat. */
113
114 /* In the absence of a native eaccessat function, here are some of
115 the implementation choices [#4 and #5 were suggested by Paul Eggert]:
116 1) call openat with O_WRONLY|O_NOCTTY
117 Disadvantage: may create the file and doesn't work for directory,
118 may mistakenly report 'unwritable' for EROFS or ACLs even though
119 perm bits say the file is writable.
120
121 2) fake eaccessat (save_cwd, fchdir, call euidaccess, restore_cwd)
122 Disadvantage: changes working directory (not reentrant) and can't
123 work if save_cwd fails.
124
125 3) if (euidaccess (full_name, W_OK) == 0)
126 Disadvantage: doesn't work if full_name is too long.
127 Inefficient for very deep trees (O(Depth^2)).
128
129 4) If the full pathname is sufficiently short (say, less than
130 PATH_MAX or 8192 bytes, whichever is shorter):
131 use method (3) (i.e., euidaccess (full_name, W_OK));
132 Otherwise: vfork, fchdir in the child, run euidaccess in the
133 child, then the child exits with a status that tells the parent
134 whether euidaccess succeeded.
135
136 This avoids the O(N**2) algorithm of method (3), and it also avoids
137 the failure-due-to-too-long-file-names of method (3), but it's fast
138 in the normal shallow case. It also avoids the lack-of-reentrancy
139 and the save_cwd problems.
140 Disadvantage; it uses a process slot for very-long file names,
141 and would be very slow for hierarchies with many such files.
142
143 5) If the full file name is sufficiently short (say, less than
144 PATH_MAX or 8192 bytes, whichever is shorter):
145 use method (3) (i.e., euidaccess (full_name, W_OK));
146 Otherwise: look just at the file bits. Perhaps issue a warning
147 the first time this occurs.
148
149 This is like (4), except for the "Otherwise" case where it isn't as
150 "perfect" as (4) but is considerably faster. It conforms to current
151 POSIX, and is uniformly better than what Solaris and FreeBSD do (they
152 mess up with long file names). */

Callers 1

promptFunction · 0.85

Calls 1

cache_fstatatFunction · 0.85

Tested by

no test coverage detected