#include #include #include #include #include #include #include #include #include #include #define PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING 1 #define PERMISSION_USER 2 #define PERMISSION_GROUP 1 #define PERMISSION_OTHERS 0 #define PERMISSION_BYTES 3 // rwx #define PERMISSION_ENTITIES 3 // user group others const int MAX_PERMISSIONS = PERMISSION_ENTITIES * PERMISSION_BYTES; typedef struct { char* username; char* groupname; char permissionStr[3][4]; char* path; } line; line* lines; int linesNo = 0; int maxUsername = 0; int maxGroupname = 0; void mallocLines() { // add one line to the lines array if (linesNo == 1) { lines = malloc(sizeof(*lines)); } else { if ((lines = realloc(lines, linesNo * sizeof(*lines))) == NULL) { fprintf(stderr, "Error allocating memory\n"); exit(4); } } } void addPermission2Line(int idx, int permissions) { strcpy(lines[idx].permissionStr[PERMISSION_USER], "---"); strcpy(lines[idx].permissionStr[PERMISSION_GROUP], "---"); strcpy(lines[idx].permissionStr[PERMISSION_OTHERS], "---"); for (int i = 0; i < MAX_PERMISSIONS; i++) { // clear out all permissions except the i'th bit int tmpPermission = permissions & (1 << i); int permissionUGO = i / PERMISSION_ENTITIES; // -1 because of 0-based index int permissionRWX = (MAX_PERMISSIONS - i - 1) % PERMISSION_BYTES; // read if (tmpPermission & S_IRUSR || tmpPermission & S_IRGRP || tmpPermission & S_IROTH) { lines[idx].permissionStr[permissionUGO][permissionRWX] = 'r'; } // write if (tmpPermission & S_IWUSR || tmpPermission & S_IWGRP || tmpPermission & S_IWOTH) { lines[idx].permissionStr[permissionUGO][permissionRWX] = 'w'; } // execute if (tmpPermission & S_IXUSR || tmpPermission & S_IXGRP || tmpPermission & S_IXOTH) { lines[idx].permissionStr[permissionUGO][permissionRWX] = 'x'; } } } void addLine(char* path, int permissions, int uid, int gid) { linesNo++; // allocate memory for another line mallocLines(); // calculate line (index) we are at, which is 0-based (thus -1) int idx = linesNo - 1; // add user struct passwd* user = getpwuid(uid); lines[idx].username = malloc(strlen(user->pw_name) + PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING); strcpy(lines[idx].username, user->pw_name); if (maxUsername < strlen(lines[idx].username)) { maxUsername = strlen(lines[idx].username); } // add group struct group* group = getgrgid(gid); lines[idx].groupname = malloc(strlen(group->gr_name) + PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING); strcpy(lines[idx].groupname, group->gr_name); if (maxGroupname < strlen(lines[idx].groupname)) { maxGroupname = strlen(lines[idx].groupname); } // calculate and add permission addPermission2Line(idx, permissions); // add current path lines[idx].path = malloc(strlen(path) + PLEASE_ADD_ONE_EXTRA_BYTE_FOR_ZERO_TERMINATED_STRING); strcpy(lines[idx].path, path); } void dumpLines() { for (int i = 0; i < linesNo; i++) { printf("%s ", lines[i].permissionStr[PERMISSION_USER]); printf("%s ", lines[i].permissionStr[PERMISSION_GROUP]); printf("%s ", lines[i].permissionStr[PERMISSION_OTHERS]); printf("%-*s ", maxUsername, lines[i].username); printf("%-*s ", maxGroupname, lines[i].groupname); printf("%s\n", lines[i].path); } } int main(int argc, char* argv[]) { if (argc > 2) { fprintf(stderr, "Usage: %s [file or directory]\n", argv[0]); exit(1); } char* path; char* startpath; path = malloc(PATH_MAX); if (argc == 1) { startpath = "."; } else { startpath = argv[1]; } if (realpath(startpath, path)) { char* base; do { struct stat sb; base = basename(path); if (stat(path, &sb) == 0) { addLine(path, sb.st_mode, sb.st_uid, sb.st_gid); } else { fprintf(stderr, "Error (%d): %s: %s\n", errno, strerror(errno), path); exit(3); } path = dirname(path); } while (strcmp(base, "/")); dumpLines(); } else { fprintf(stderr, "Error (%d): %s: %s\n", errno, strerror(errno), path); exit(2); } free(path); }