操作系统第4次实验报告:文件系统
- 姓名:白晓
- 学号:201821121035
- 班级:计算1812
1. 编写程序
在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai
的功能,给出源代码。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<dirent.h> 6 #include<sys/stat.h> 7 #include<sys/types.h> 8 #include<fcntl.h> 9 #include<time.h> 10 #include<pwd.h> 11 #include<grp.h> 12 13 #define PARAMETER_NONE 0 14 #define PARAMETER_A 1 15 #define PARAMETER_L 2 16 #define MAXROWLEN 80 17 int g_leave_len = MAXROWLEN; 18 int g_maxlen; 19 void error(const char *err_string, int line); 20 void Demonstrate_attribute(struct stat buf, char * name); 21 void Demonstrate_single(char * name); 22 void Demonstrate(int flag, char * pathname); / 23 void Demonstrate_dir(int flag_parameter, char * path); 24 25 int main(int argc, char ** argv){ 26 int i, j, k, num; 27 char path[PATH_MAX+1]; //文件路径名 28 char parameter[32]; // 保存命令行参数 29 int flag_parameter = PARAMETER_NONE; // 用来标志参数种类 30 struct stat buf; 31 j = 0, 32 num = 0; 33 for (i = 1 ; i < argc; i++){ 34 if (argv[i][0] == '-'){ 35 for(k = 1; k < strlen(argv[i]); k++){ 36 parameter[j] = argv[i][k]; // 获取-后面的参数保存到数组parameter中 37 j++; 38 } 39 num++; // 保存"-"的个数 40 } 41 } 42 for(i = 0; i < j; i++){ 43 if (parameter[i] == 'a'){ 44 flag_parameter = PARAMETER_A; 45 continue; 46 } 47 else if (parameter[i] == 'l'){ 48 flag_parameter = PARAMETER_L; 49 continue; 50 } 51 else{ 52 printf("my_ls: invalid option -%c\n", parameter[i]); 53 exit(1); 54 } 55 } 56 parameter[j] = '\0'; 57 if ((num + 1) == argc){ 58 strcpy(path, "./");// "./"当前目录 59 path[2] = '\0'; 60 Demonstrate_dir(flag_parameter, path); 61 return 0; 62 } 63 i=1; 64 do { 65 if (argv[i][0] == '-'){ 66 i++; 67 continue; 68 } 69 else{ 70 strcpy(path, argv[i]); 71 if ( stat(path, &buf) == -1 ){ 72 error("stat", __LINE__); 73 } 74 if ( S_ISDIR(buf.st_mode) ) // argv[i]是一个目录{ 75 if ( path[ strlen(argv[i])-1 ] != '/'){ 76 path[ strlen(argv[i]) ] = '/'; 77 path[ strlen(argv[i])+1 ] = '\0'; 78 } 79 else{ 80 path[ strlen(argv[i]) ] = '\0'; 81 } 82 Demonstrate_dir(flag_parameter,path); 83 i++; 84 } 85 else{ 86 Demonstrate(flag_parameter, path); 87 i++; 88 } 89 } 90 } while (i < argc); 91 return 0; 92 } 93 void error(const char *err_string, int line){ 94 fprintf(stderr, "line:%d ", line); 95 perror(err_string); 96 exit(1); 97 } 98 void Demonstrate_attribute(struct stat buf, char * name){ 99 char buf_time[32]; //存放时间 100 struct passwd *psd; //从该结构体中获取文件所有者的用户名 101 struct group *grp; //从该结构体中获取文件所有者所属组的组名 102 if (S_ISLNK(buf.st_mode)){ 103 printf("l"); 104 } 105 else if (S_ISREG(buf.st_mode)){ 106 printf("-"); 107 } 108 else if (S_ISDIR(buf.st_mode)){ 109 printf("d"); 110 } 111 else if (S_ISCHR(buf.st_mode)){ 112 printf("c"); 113 } 114 else if (S_ISBLK(buf.st_mode)){ 115 printf("b"); 116 } 117 else if (S_ISFIFO(buf.st_mode)){ 118 printf("f"); 119 } 120 else if (S_ISSOCK(buf.st_mode)){ 121 printf("s"); 122 } 123 if (buf.st_mode & S_IRUSR){ 124 printf("r"); 125 } 126 else{ 127 printf("-"); 128 } 129 if (buf.st_mode & S_IWUSR){ 130 printf("w"); 131 } 132 else{ 133 printf("-"); 134 } 135 if (buf.st_mode & S_IXUSR){ 136 printf("x"); 137 } 138 else{ 139 printf("-"); 140 } 141 if (buf.st_mode & S_IRGRP){ 142 printf("r"); 143 } 144 else{ 145 printf("-"); 146 } 147 if (buf.st_mode & S_IWGRP) 148 { 149 printf("w"); 150 } 151 else{ 152 printf("-"); 153 } 154 if (buf.st_mode & S_IXGRP){ 155 printf("x"); 156 } 157 else{ 158 printf("-"); 159 } 160 if (buf.st_mode & S_IROTH){ 161 printf("r"); 162 } 163 else{ 164 printf("-"); 165 } 166 if (buf.st_mode & S_IWOTH){ 167 printf("w"); 168 } 169 else 170 { 171 printf("-"); 172 } 173 if (buf.st_mode & S_IXOTH){ 174 printf("x"); 175 } 176 else{ 177 printf("-"); 178 } 179 printf(" "); 180 psd = getpwuid(buf.st_uid); 181 grp = getgrgid(buf.st_gid); 182 printf("%4d ",buf.st_nlink); //打印文件的链接数 183 printf("%-9s", psd->pw_name); //打印文件拥有者 184 printf("%-8s", grp->gr_name); //打印文件所属用户组 185 printf("%6d",(int)buf.st_size); // 打印文件的大小 186 strcpy(buf_time, ctime(&buf.st_mtime)); 187 buf_time[strlen(buf_time) - 1] = '\0'; // 去掉换行符 188 printf(" %s", buf_time); // 打印文件的时间信息 189 } 190 void Demonstrate_single(char *name){ 191 int i, len; 192 if (g_leave_len < g_maxlen){ 193 printf("\n"); 194 g_leave_len = MAXROWLEN; 195 } 196 len = strlen(name); 197 len = g_maxlen - len; 198 printf("%-s", name); 199 for (i = 0; i < len; i++){ 200 printf(" "); 201 } 202 printf(" "); 203 g_leave_len -= (g_maxlen + 2); 204 } 205 void Demonstrate(int flag, char * pathname){ 206 int i, j; 207 struct stat buf; 208 char name[NAME_MAX + 1]; 209 for (i = 0, j = 0; i < strlen(pathname); i++){ 210 if (pathname[i] == '/'){ 211 j = 0; 212 continue; 213 } 214 name[j++] = pathname[i]; 215 } 216 name[j] = '\0'; 217 if ( lstat(pathname, &buf) == -1 ){ 218 error("stat", __LINE__); 219 } 220 switch (flag){ 221 case PARAMETER_NONE: // 没有-l和-a选项 222 if (name[0] != '.'){ 223 Demonstrate_single(name); 224 } 225 break; 226 case PARAMETER_A: // -a:显示包括隐藏文件在内的所有文件 227 Demonstrate_single(name); 228 break; 229 case PARAMETER_L: // -l:每个文件单独占一行,显示文件的详细属性信息 230 if (name[0] != '.'){ 231 Demonstrate_attribute(buf, name); 232 printf(" %-s\n", name); 233 } 234 break; 235 case PARAMETER_A + PARAMETER_L: // 同时有-a和-l选项的情况 236 Demonstrate_attribute(buf, name); 237 printf(" %-s\n", name); 238 break; 239 default: 240 break; 241 } 242 } 243 void Demonstrate_dir(int flag_parameter, char *path){ 244 DIR *dir; 245 struct dirent *ptr; 246 int count = 0; 247 char filenames[256][PATH_MAX + 1],temp[PATH_MAX + 1];// 获取该目录下文件总数和最长的文件名 248 dir = opendir(path); 249 if (dir == NULL){ 250 error("opendir", __LINE__); 251 } 252 while ((ptr = readdir(dir)) != NULL){ 253 if (g_maxlen < strlen(ptr->d_name)) 254 g_maxlen = strlen(ptr->d_name); 255 count++; 256 } 257 closedir(dir); 258 if(count > 256) 259 error("too many files under this dir",__LINE__); 260 int i, j, len = strlen(path);// 获取该目录下所有的文件名 261 dir = opendir(path); 262 for(i = 0; i < count; i++){ 263 ptr = readdir(dir); 264 if( ptr == NULL){ 265 error("readdir",__LINE__); 266 } 267 strncpy(filenames[i],path,len); //filenames存放目录下的所有文件名 268 filenames[i][len] = '\0'; 269 strcat(filenames[i],ptr->d_name); 270 filenames[i][len + strlen(ptr->d_name)] = '\0'; 271 } 272 for(i = 0; i < count-1; i++) 273 for(j = 0; j < count - 1 - i; j++) 274 { 275 if( strcmp(filenames[j],filenames[j + 1]) > 0 ) 276 { 277 strcpy(temp,filenames[j + 1]); 278 temp[strlen(filenames[j + 1])] = '\0'; 279 strcpy(filenames[j + 1],filenames[j]); 280 filenames[j + 1][strlen(filenames[j])] = '\0'; 281 strcpy(filenames[j], temp); 282 filenames[j][strlen(temp)] = '\0'; 283 } 284 } 285 for(i = 0; i < count; i++) 286 Demonstrate(flag_parameter, filenames[i]); 287 closedir(dir); 288 if( (flag_parameter & PARAMETER_L) == 0) 289 printf("\n"); 290 }
2. 分析运行结果
给出运行结果截图,对于每一列是如何获取的,结合源代码做解释
获取文件权限:
1 if (S_ISLNK(buf.st_mode)){ 2 printf("l"); 3 } 4 else if (S_ISREG(buf.st_mode)){ 5 printf("-"); 6 } 7 else if (S_ISDIR(buf.st_mode)){ 8 printf("d"); 9 } 10 else if (S_ISCHR(buf.st_mode)){ 11 printf("c"); 12 } 13 else if (S_ISBLK(buf.st_mode)){ 14 printf("b"); 15 } 16 else if (S_ISFIFO(buf.st_mode)){ 17 printf("f"); 18 } 19 else if (S_ISSOCK(buf.st_mode)){ 20 printf("s"); 21 } 22 if (buf.st_mode & S_IRUSR){ 23 printf("r"); 24 } 25 else{ 26 printf("-"); 27 } 28 if (buf.st_mode & S_IWUSR){ 29 printf("w"); 30 } 31 else{ 32 printf("-"); 33 } 34 if (buf.st_mode & S_IXUSR){ 35 printf("x"); 36 } 37 else{ 38 printf("-"); 39 } 40 if (buf.st_mode & S_IRGRP){ 41 printf("r"); 42 } 43 else{ 44 printf("-"); 45 } 46 if (buf.st_mode & S_IWGRP) 47 { 48 printf("w"); 49 } 50 else{ 51 printf("-"); 52 } 53 if (buf.st_mode & S_IXGRP){ 54 printf("x"); 55 } 56 else{ 57 printf("-"); 58 } 59 if (buf.st_mode & S_IROTH){ 60 printf("r"); 61 } 62 else{ 63 printf("-"); 64 } 65 if (buf.st_mode & S_IWOTH){ 66 printf("w"); 67 } 68 else 69 { 70 printf("-"); 71 } 72 if (buf.st_mode & S_IXOTH){ 73 printf("x"); 74 } 75 else{ 76 printf("-"); 77 }
文件的大小、文件最后的修改时间、文件名:
1 printf("%4d ",buf.st_nlink); //打印文件的链接数 2 printf("%-9s", psd->pw_name); //打印文件拥有者 3 printf("%-8s", grp->gr_name); //打印文件所属用户组 4 printf("%6d",(int)buf.st_size); // 打印文件的大小 5 strcpy(buf_time, ctime(&buf.st_mtime)); 6 buf_time[strlen(buf_time) - 1] = '\0'; // 去掉换行符 7 printf(" %s", buf_time); // 打印文件的时间信息
3. 通过该实验产生新的疑问及解答
opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列
readdir:struct dirent *readdir(DIR *dirp), 把opendir的返回值传过来, 返回值为一个结构体