-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchown.h
88 lines (85 loc) · 2.95 KB
/
chown.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright (C) 2021 Benjamin Stürz
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef FILE_CHOWN_H
#define FILE_CHOWN_H
static int opt_h, opt_upper, recursive, initial;
static bool do_chown(const char* path, uid_t uid, gid_t gid) {
int rv = true;
struct stat st;
int error;
if (opt_h || recursive) error = lstat(path, &st);
else error = stat(path, &st);
if (error != 0) {
errprintf("failed to access '%s", path);
return false;
}
if ((st.st_mode & S_IFMT) == S_IFLNK) {
if (opt_upper == 'P' || opt_h) {
if (lchown(path, uid, gid) != 0) {
errprintf("failed to change owner for '%s'", path);
return false;
}
return true;
}
if (opt_upper == 'L' || (opt_upper == 'H' && initial)) {
if (opt_h) {
if (lchown(path, uid, gid) != 0) {
errprintf("failed to change owner for '%s'", path);
return false;
}
}
if (stat(path, &st) != 0) {
errprintf("failed to resolve symoblic link '%s'", path);
return false;
}
}
}
if (recursive && (st.st_mode & S_IFMT) == S_IFDIR) {
// path is a directory
const size_t len = strlen(path);
DIR* dir;
struct dirent* ent;
char* buffer = (char*)malloc(len + sizeof(ent->d_name) + 4);
if (!buffer) {
errprintf("failed to allocate buffer");
return false;
}
if ((dir = opendir(path)) == NULL) {
errprintf("failed to access '%s'", path);
return false;
}
memcpy(buffer, path, len);
buffer[len] = '/';
while ((ent = readdir(dir)) != NULL) {
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0) continue;
strncpy(buffer + len + 1, ent->d_name, 0 + sizeof(ent->d_name)); // '0 + ...' to suppress warnings on gcc
initial = false;
if (!do_chown(buffer, uid, gid)) {
//fprintf(stderr, "chown: failed to change owner of '%s': %s\n", buffer, strerror(errno));
rv = false;
}
}
free(buffer);
closedir(dir);
}
if (opt_h) error = lchown(path, uid, gid);
else error = chown(path, uid, gid);
if (error != 0) {
errprintf("failed to change owner for '%s'", path);
return false;
}
return rv;
}
#endif /* FILE_CHOWN_H */