-
-
Save l1fe/5564332 to your computer and use it in GitHub Desktop.
a simple recursive LS for *nix (memory leaks due shitty getpwuid && getgrgid)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <dirent.h> | |
| #include <unistd.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <assert.h> | |
| #include <errno.h> | |
| #include <time.h> | |
| #include <string.h> | |
| #include <pwd.h> | |
| #include <grp.h> | |
| #include <stdbool.h> | |
| typedef struct file_info file_info; | |
| typedef struct queue queue; | |
| void queue_init(const queue* q); | |
| void print_dir(const char* dirname); | |
| const char* joinpath(const char* dirname, const char* filename); | |
| void print_file(const char* dirname, struct dirent* entry, bool rec); | |
| char* get_username(uid_t uid); | |
| char* get_grpname(gid_t gid); | |
| void set_perms(struct stat* const buf, char perms[10]); | |
| void print_file_info(const file_info* curfile_info); | |
| typedef struct file_info { | |
| char* usr_name; | |
| char* grp_name; | |
| char perms[10]; | |
| int links_n; | |
| struct tm* time; | |
| size_t size; | |
| } file_info; | |
| const char* joinpath(const char* dirname, const char* filename) { | |
| assert(dirname != NULL && NULL != filename); | |
| char* result = malloc(strlen(dirname) + strlen(filename) + 2); | |
| if (NULL == result) | |
| return NULL; | |
| strcpy(result, dirname); | |
| strcat(result, "/"); | |
| strcat(result, filename); | |
| return result; | |
| } | |
| char* get_username(uid_t uid) { | |
| struct passwd* pwd = getpwuid(uid); | |
| if (NULL == pwd) | |
| return NULL; | |
| char* retVal = pwd->pw_name; | |
| return retVal; | |
| } | |
| char* get_groupname(gid_t gid) { | |
| struct group* grp = getgrgid(gid); | |
| if (NULL == grp) | |
| return NULL; | |
| char* retVal = grp->gr_name; | |
| return retVal; | |
| } | |
| void set_perms(struct stat* const buf, char perms[10]) { | |
| const char mode[3] = {'r', 'w', 'x'}; | |
| const int flags[9] = {S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH}; | |
| memset(perms, '-', 10); | |
| if ((buf->st_mode & S_IFMT) == S_IFDIR) | |
| perms[0] = 'd'; | |
| int i; | |
| for (i = 0; i < 9; ++i) { | |
| if ((buf->st_mode & flags[i])) | |
| perms[i + 1] = mode [ i % 3 ]; | |
| } | |
| } | |
| void print_file_info(const file_info* curfile_info) { | |
| int i; | |
| for (i = 0; i < 10; ++i) | |
| printf("%c", curfile_info->perms[i]); | |
| printf(" %d", curfile_info->links_n); | |
| printf(" %s %s", curfile_info->usr_name, curfile_info->grp_name); | |
| printf(" %6d", curfile_info->size); | |
| printf(" %02d-%02d-%02d %02d:%02d ", curfile_info->time->tm_year + 1900, | |
| curfile_info->time->tm_mon, | |
| curfile_info->time->tm_mday, | |
| curfile_info->time->tm_hour, | |
| curfile_info->time->tm_min); | |
| } | |
| void print_file(const char* dirname, struct dirent* entry, bool rec) { | |
| const char* filepath = joinpath(dirname, entry->d_name); | |
| if (NULL == filepath) { | |
| fprintf(stderr, "not enough memory"); | |
| return; | |
| } | |
| file_info curfile_info; | |
| struct stat buf; | |
| if (-1 == lstat(filepath, &buf)) { | |
| fprintf(stderr, "can't open file"); | |
| free((void*)filepath); | |
| return; | |
| } | |
| if (!rec) { | |
| set_perms(&buf, curfile_info.perms); | |
| curfile_info.links_n = buf.st_nlink; | |
| if (NULL == (curfile_info.usr_name = get_username(buf.st_uid))) | |
| fprintf(stderr, "error: can't obtain username of file"); | |
| if (NULL == (curfile_info.grp_name = get_groupname(buf.st_gid))) | |
| fprintf(stderr, "error: can't obtain groupname of file"); | |
| curfile_info.size = buf.st_size; | |
| curfile_info.time = localtime((time_t*)&buf.st_mtime); | |
| print_file_info(&curfile_info); | |
| printf("%40s", entry->d_name); | |
| if (S_ISDIR(buf.st_mode)) printf(" [directory]\n"); | |
| else if (S_ISREG(buf.st_mode)) printf(" [regular file]\n"); | |
| else if (S_ISCHR(buf.st_mode)) printf(" [char. device]\n"); | |
| else if (S_ISBLK(buf.st_mode)) printf(" [block device]\n"); | |
| else if (S_ISFIFO(buf.st_mode)) printf(" [FIFO]\n"); | |
| else if (S_ISLNK(buf.st_mode)) printf(" [symb. link]\n"); | |
| else if (S_ISSOCK(buf.st_mode)) printf(" [socket]\n"); | |
| } else { | |
| if (S_ISDIR(buf.st_mode)) { | |
| const char* nextdir = joinpath(dirname, entry->d_name); | |
| print_dir(nextdir); | |
| free((void*)nextdir); | |
| } | |
| } | |
| free((void*)filepath); | |
| } | |
| void print_dir(const char* dirname) { | |
| DIR* curDir = opendir(dirname); | |
| if (NULL == curDir) { | |
| fprintf(stderr, "can't open directory %s\n", dirname); | |
| return; | |
| } | |
| printf("%s:\n", dirname); | |
| struct dirent* curFile; | |
| int files_count = 0; | |
| while ((NULL != (curFile = readdir(curDir)))) | |
| if (0 != strcmp("..", curFile->d_name) && 0 != strcmp(".", curFile->d_name)) | |
| ++files_count; | |
| printf("total files: %d\n", files_count); | |
| rewinddir(curDir); | |
| while ((NULL != (curFile = readdir(curDir)))) { | |
| if (0 != strcmp("..", curFile->d_name) && 0 != strcmp(".", curFile->d_name)) | |
| print_file(dirname, curFile, 0); | |
| } | |
| rewinddir(curDir); | |
| while ((NULL != (curFile = readdir(curDir)))) { | |
| if (0 != strcmp("..", curFile->d_name) && 0 != strcmp(".", curFile->d_name)) | |
| print_file(dirname, curFile, 1); | |
| } | |
| closedir(curDir); | |
| } | |
| int main(int argc, char* argv[]) { | |
| char* dirName; | |
| if (argc < 2) | |
| dirName = "."; | |
| else | |
| dirName = argv[1]; | |
| print_dir(dirName); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment