CS202 Review Session 2 Notes from [Xiangyu Gao](https://xiangyug.github.io/), TA from fall 2021 Edited by Khanh Nguyen, TA Spring 2022 1. C review (continued) 2. Lab 2 overview 3. Q&A --------------------------------------------------------------------- "There's no magic in systems" Personally, I think this is very reassuring. It gives me lots of confidence in learning about different systems and reading through the code. Hopefully, it gives you more confidence in reading, learning and building systems as well! 1. C review (continued) a. String concatenation - There are many ways to concatenate strings: strcat, strncat, etc... - I'd avoid using strcat because it can lead to buffer overflow if you are not careful. Lab 2 suggests using snprintf (learn more by `man snprintf`), which I think is very handy. int snprintf(char *str, size_t size, const char *format, ...) - char *str: buffer to write INTO (or in other word, the output after concatenation) - size_t size: maximum size to write into the buffer - char *format: format for the concatenation, similar to how you would use in printf - ...: optional arguments. this means you can provide 2,3,4 or more string to concatenate. [See example in the whiteboard] b. Struct - C doesn't have a concept of class, like in Java, but it has `struct`. Struct is a collection of data items grouped into a single thing. - You can define a struct as: ``` struct student { int age; char* name; } ``` - To initialize: ``` struct student alice; alice.age = 22; alice.name = "Alice"; ``` - struct can contain any number of variables, including pointers. In lab 2, you will deal with struct pointer. - For example: ``` struct student *palice = &alice; ``` Mental model: | age = 22 | <---- alice. addr: 0x100 | name = "Alice" | | 0x100 | <---- palice - To access members of the struct, you can do: ``` *palice.age; OR palice->age; // -> operator = dereference and then access the member ``` 2. Lab 2 overview a. Motivation - You will implement ls, which is a command, in lab 2. - It will help you practice reading man pages, working with system calls, toying with the APIs, and design as well as re-design/refactor your code. b. File definition - Normal files can be: "test.txt", "main.c", ... - Normal directories can be: "foo/", "bar/", "foo/bar/", ... - Some files and directories start with ".". If you are curious, you can inspect ".git" in your repository. This is where git stores your information and commit history. These are usually hidden from the users when they invoke `ls`. Specifically, to see them, you would need `ls -a` - In addition, "." also means current directory. ".." means parent directory. Every directory you create will have these 2 "pseudo-directories". - With that, there are also relative and absolute path: + Relative is a path from the current directory. Usually, it prefixes with "." and "..". For instance: `./my/relative/path/to/file`. +_Absolute path is a path from the fullpath you are providing. For instance: `~/my/absolute/path`. c. File permissions - Lab 2 wil have you print the permission of a file, which has the form: rwx------. There are 10 chars, but we are concerned with the last 9. - In the 9 chars, the first group of 3 chars refers to user's permission, the second group of 3 chars refers to the groupm the last 3 chars refer to everybody else. - Sometimes you would see people do: `chmod 700 file.txt`. - The way to read it is split 700 into 3 characters so 7,0,0. Then convert to binary. Each character then represent the same file permission as the 9 characters we saw earlier. A 1 in binary means the bit is set. A 0 means otherwise. Example: 700 -> 7,0,0 -> 111,000,000 -> rwx------ d. Flags - ` ./ls -alR foo/ bar/` | program | flags | args - Flags refer to -a, -l, -R. You will need to support combination of them as well. - To make it more clear, let's look at getopt() (learn more `man 3 getopt`). int getopt(int argc, char* const argv[], const char *optstring) - argc: number of arguments supplied (from main) - argv: array of arguments supplied (from main) - optstring: the flag we want to parse - optind: a global variable specifying the index in argv to parse the next time - around, initialized to 1. If getopt() finds another option character, from the optstring you provided, in the arguments supplied, it returns that character, updating the variable optind so the next call to getopt() can resume the scan. It returns -1 otherwise. Example: // Example from man 3 getopt #include #include #include int main(int argc, char *argv[]) { int flags, opt; int nsecs, tfnd; nsecs = 0; tfnd = 0; flags = 0; while ((opt = getopt(argc, argv, "nt:")) != -1) { switch (opt) { case 'n': flags = 1; break; case 't': nsecs = atoi(optarg); tfnd = 1; break; default: /* '?' */ fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]); exit(EXIT_FAILURE); } } printf("flags=%d; tfnd=%d; nsecs=%d; optind=%d\n", flags, tfnd, nsecs, optind); if (optind >= argc) { fprintf(stderr, "Expected argument after options\n"); exit(EXIT_FAILURE); } printf("name argument = %s\n", argv[optind]); /* Other code omitted */ exit(EXIT_SUCCESS); } - Will parse -n and -t. - Expect at least 1 argument after the flag - Try compile, run and observe the output: `./a.out -n`, `./a.out -t`, `./a.out -nt`, `./a.out -n foo bar` - getopt_long is quite similar. The exception is that getopt_long allows us to parse flag in long format, which prefixes with `--` instead of `-` - Read about getopt_long: `man 3 getopt_long` e. Functions: - The main building blocks of you program is: opendir, readdir and closedir. - Read through their man pages carefully. - Don't forget to call closedir when you finish with your function. We don't want resources to be leaked. f. Helper functions: - We provide lots of handy helper functions and macros such as: - PRINT_PERM_CHAR: print out the corresponding permission character - uname_for_uid: convert to human-readable user id - group_for_uid: convert to human-readable group id - date_string: convert to formatted date string - ftype_to_string: print out the file type - Please read through them carefully. Lots of students try to reinvent their own way of doing this, which is more painful than necessary. g. Test output: - Part of the lab is figuring out what it is testing. Don't be intimidated if your test output is really big and strange. - We run diff between your output (./ls) and system output (ls). - diff command: `diff your_output.txt system_output.txt` Example: 2,3c1,3 < < < ---- > > > - In the example above, everything in the 2nd line, before `---`, is your output. The rest is the system output. Or in other word, everything before `---` is result of file on the left of the diff command and everything after is result of the file on the right. It's showing the difference between your output and system output. - The first line, `2,3c1,3` refers to what needs to be changed so that the differences are resolved. - `2,3c1,3`: Your file, line 2-3 needs to be changed to system file, line 1-3. - c: change - a: add - d: delete