Author | Jamozed <[email protected]> |
Date | 2020-11-16 12:23:57 |
Commit | 72364dd43c95e99112f6fa96735ce1b03e541c5a |
Parent | 70ce5b01e577b7b480ce65f9c471de1336660d47 |
chmod: Handle R flag
Diffstat
M | src/chmod.c | | | 52 | +++++++++++++++++++++++++++++++++++++++++++--------- |
M | src/mkdir.c | | | 2 | +- |
2 files changed, 44 insertions, 10 deletions
diff --git a/src/chmod.c b/src/chmod.c index c6dc1e0..a301e9a 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -1,4 +1,4 @@ -// chmod.c, version 1.0.0 +// chmod.c, version 1.0.1 // OMKOV coreutils implementation of POSIX chmod // Copyright (C) 2020, Jakob Wakeling // All rights reserved. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. */ /* - TODO Handle R flag + TODO Don't recursively change symlink permissions TODO Handle copying permission */ @@ -39,14 +39,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. #include "lib/mode.h" #include "lib/optget.h" +#include <dirent.h> #include <sys/stat.h> +#include <unistd.h> #include <errno.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> -#define VERSION "1.0.0" +#define VERSION "1.0.1" static struct lop lops[] = { { "help", ARG_NUL, 256 }, @@ -57,8 +60,10 @@ static struct lop lops[] = { static bool Rflag; static mode_t mask; +static bool warned = false; -static inline int setmode(const char *path, chmod_t *m); +static inline int setmode(const char *path, chmod_t *m); +static inline char *mkpath(const char *path, const char *file); static void hlp(void); static void ver(void); @@ -77,19 +82,20 @@ int main(int ac, char *av[]) { A0 = av[0]; mask = umask(0); chmod_t *m = strmode(av[opt.ind]); if (!m) { error(1, "%s: invalid mode", av[opt.ind]); } - bool warned = false; - for (char **p = &av[opt.ind + 1]; *p; ++p) { if (setmode(*p, m)) { warn("%s: %s", *p, serr()); warned = true; } } - if (m) { free(m); } return warned; + free(m); return warned; } /* Set the mode of the specified file */ static inline int setmode(const char *path, chmod_t *m) { + struct stat st; register bool ln = false; + // Get current permissions of file - struct stat st; if (stat(path, &st)) { return 1; }; + if (lstat(path, &st)) { return 1; }; + if (S_ISLNK(st.st_mode)) { if (stat(path, &st)) { return 1; } ln = true; } mode_t mode = st.st_mode; // Handle each chmod_t @@ -114,7 +120,35 @@ static inline int setmode(const char *path, chmod_t *m) { } end:; // Set permissions of the file to the calculated mode - if (chmod(path, mode)) { return 1; } return 0; + if (chmod(path, mode)) { return 1; } + + // Recurse into directories if R flag is set + if (Rflag && !ln && S_ISDIR(st.st_mode)) { + DIR *di; if (!(di = opendir(path))) { return 1; } + + // For each entry in directory, recursively call setmode + for (struct dirent *de; (de = readdir(di));) { + if (de->d_name[0] == '.' && (de->d_name[1] == 0 || + (de->d_name[1] == '.' && de->d_name[2] == 0))) { continue; } + + char *s = mkpath(path, de->d_name); + if (setmode(s, m)) { warn("%s: %s", s, serr()); warned = true; } + + free(s); + } + + closedir(di); + } + + return 0; +} + +/* Allocate and make path from two components */ +static inline char *mkpath(const char *path, const char *file) { + register size_t pl = strlen(path); char *s; + s = (char *)malloc((pl + strlen(file) + 2) * sizeof (*s)); + strcpy(s, path); if (s[pl - 1] != '/') { s[pl] = '/'; s[++pl] = 0; } + strcat(s, file); return s; } /* Print help information */ diff --git a/src/mkdir.c b/src/mkdir.c index a29dd45..0d3fbf3 100644 --- a/src/mkdir.c +++ b/src/mkdir.c @@ -98,7 +98,7 @@ int main(int ac, char *av[]) { A0 = av[0]; if (makedir(*p, m)) { warn("%s: %s", *p, serr()); warned = true; } } - if (m) { free(m); } return warned; + free(m); return warned; } /* Make directory with specified permissions */