#define _GNU_SOURCE #include #include #include #include #include #include #include #include #define MAX_PATH_LEN 4096 static void usage (void) __attribute__ ((unused)); // WARNING WARNING WARNING: // When using opendir and readdir to read directory listings, the files // are returned in the order they were created. There is randomness to that // creation that can cause tests to fail. You MUST sort the file names as // expected in the test case files. To avoid making your task harder than // it needs to be, we strongly suggest you use scandir instead. int filename_cmp (const struct dirent **a, const struct dirent **b) { const char *name1 = (*a)->d_name; const char *name2 = (*b)->d_name; while (*name1 == '.') name1++; while (*name2 == '.') name2++; return strcasecmp (name1, name2); } void print_permissions (mode_t mode) { char perms[11]; perms[0] = S_ISDIR (mode) ? 'd' : '-'; perms[1] = (mode & S_IRUSR) ? 'r' : '-'; perms[2] = (mode & S_IWUSR) ? 'w' : '-'; perms[3] = (mode & S_IXUSR) ? 'x' : '-'; perms[4] = (mode & S_IRGRP) ? 'r' : '-'; perms[5] = (mode & S_IWGRP) ? 'w' : '-'; perms[6] = (mode & S_IXGRP) ? 'x' : '-'; perms[7] = (mode & S_IROTH) ? 'r' : '-'; perms[8] = (mode & S_IWOTH) ? 'w' : '-'; perms[9] = (mode & S_IXOTH) ? 'x' : '-'; perms[10] = '\0'; printf ("%s", perms); } int main (int argc, char *argv[]) { int opt; int a_flag = false, p_flag = false, s_flag = false; while ((opt = getopt (argc, argv, "aps")) != -1) { switch (opt) { case 'a': a_flag = true; break; case 'p': p_flag = true; break; case 's': s_flag = true; break; default: printf ("./bin/ls: invalid option -- \'%c\'\n", optopt); exit (EXIT_FAILURE); } } char *dirname = optind < argc ? argv[optind] : "."; struct stat dirstat; if (stat(dirname, &dirstat) != 0) { return EXIT_FAILURE; } struct dirent **namelist; int n = scandir (dirname, &namelist, NULL, filename_cmp); for (int i = 0; i < n; i++) { char path[MAX_PATH_LEN]; snprintf (path, sizeof (path), "%s/%s", dirname, namelist[i]->d_name); struct stat st; lstat (path, &st); bool dot_dir = strcmp (namelist[i]->d_name, ".") == 0 || strcmp (namelist[i]->d_name, "..") == 0; bool hidden = namelist[i]->d_name[0] == '.'; if (dot_dir || (!a_flag && hidden) || (s_flag && S_ISDIR (st.st_mode))) { free (namelist[i]); continue; } if (s_flag) { printf ("%ld ", st.st_size); } if (p_flag) { print_permissions (st.st_mode); printf (" "); } printf ("%s\n", namelist[i]->d_name); free (namelist[i]); } free (namelist); return EXIT_SUCCESS; } static void usage (void) { printf ("ls, list directory contents\n"); printf ("usage: ls [FLAG ...] [DIR]\n"); printf ("FLAG is one or more of:\n"); printf (" -a list all files (even hidden ones)\n"); printf (" -p list permission bitmask\n"); printf (" -s list file sizes\n"); printf ("If no DIR specified, list current directory contents.\n\n"); printf ("Files must be sorted alphabetically, case insensitive.\n"); printf ("Leading dots should be ignored when sorting.\n\n"); printf ("With the -s flag, do not show entries for subdirectories.\n"); printf ("Permission bitmasks are 10-character strings such as:\n"); printf (" -rwxr-x---\n\n"); printf ( "The first character is d for directories and - for regular files.\n\n"); printf ("Do not show the \".\" or \"..\" directory entries.\n"); }