├── Makefile ├── README.md ├── reference └── dirtree ├── src └── dirtree.c └── tools ├── demo.tree ├── gentree.sh ├── mksock ├── test1.tree ├── test2.tree └── test3.tree /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------------------------- 2 | # System Programming I/O Lab Spring 2024 3 | # 4 | # Makefile 5 | # 6 | # GNU make documentation: https://www.gnu.org/software/make/manual/make.html 7 | # 8 | # You shouldn't have to modify anything in this Makefile unless you add new source files. 9 | # 10 | 11 | #--- variable declarations 12 | 13 | # directories 14 | SRC_DIR=src 15 | OBJ_DIR=obj 16 | DEP_DIR=.deps 17 | 18 | # C compiler and compilation flags 19 | CC=gcc 20 | CFLAGS=-Wall -Wno-stringop-truncation -O2 -g 21 | CFLAGS_HDT=-Wall -Wno-stringop-truncation -O2 22 | DEPFLAGS=-MMD -MP -MT $@ -MF $(DEP_DIR)/$*.d 23 | 24 | # make sure SOURCES includes ALL source files required to compile the project 25 | SOURCES=dirtree.c 26 | TARGET=dirtree 27 | 28 | # derived variables 29 | OBJECTS=$(SOURCES:%.c=$(OBJ_DIR)/%.o) 30 | DEPS=$(SOURCES:%.c=$(DEP_DIR)/%.d) 31 | 32 | 33 | #--- rules 34 | .PHONY: doc 35 | 36 | all: $(TARGET) 37 | 38 | $(TARGET): $(OBJECTS) 39 | $(CC) $(CFLAGS) -o $@ $^ 40 | 41 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(DEP_DIR) $(OBJ_DIR) 42 | $(CC) $(CFLAGS) $(DEPFLAGS) -o $@ -c $< 43 | 44 | $(DEP_DIR): 45 | @mkdir -p $(DEP_DIR) 46 | 47 | $(OBJ_DIR): 48 | @mkdir -p $(OBJ_DIR) 49 | 50 | -include $(DEPS) 51 | 52 | doc: $(SOURES:%.c=$(SRC_DIR)/%.c) $(wildcard $(SOURCES:%.c=$(SRC_DIR)/%.h)) 53 | doxygen doc/Doxyfile 54 | 55 | clean: 56 | rm -rf $(OBJ_DIR) $(DEP_DIR) 57 | 58 | mrproper: clean 59 | rm -rf $(TARGET) doc/html 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lab 2: I/O 2 | 3 | In this lab, we implement a tool that lists all files in a directory and all its subdirectories. 4 | 5 | You will learn 6 | * how to iterate through all files in a directory 7 | * how to retrieve the metadata of a file 8 | * how to print nicely formatted output 9 | * that error handling requires a significant effort 10 | * that string handling is not one of C's strengths 11 | * and a bunch of other useful programming tricks and C library functions 12 | 13 | ## Important Dates 14 | 15 | | Date | Description | 16 | |:--- |:--- | 17 | | Tuesday, March 19, 18:30 | I/O Lab hand-out | 18 | | Tuesday, March 26, 18:30 | I/O Lab session 1 | 19 | | Tuesday, April 2, 18:30 | I/O Lab session 2 | 20 | | Wednesday, April 3, 23:59 | Submission deadline | 21 | 22 | 23 | ## Logistics 24 | 25 | ### Hand-out 26 | 27 | You can clone this repository directly on your VM instance or local computer and get to work. If you want to keep your own repository, you should **keep the lab's visibility to private**. Otherwise, others would see your work. Read the instructions here carefully. 28 | 29 | #### Changing visibility 30 | 31 | After cloning the repository, you should change the push remote URL to your own repository. 32 | 1. Create an empty repository that you're going to manage **(again, keep it private)** 33 | 2. Copy the url of that repository 34 | 3. On your terminal in the cloned directory, type `git remote set-url --push origin ` 35 | 4. Check with `git remote -v` if the push URL has changed to yours while the fetch URL remains the same (this repo) 36 | 37 | 38 | ### Submission 39 | 40 | You should upload your archive file(.tar) containing code (dirtree.c) and report (20XX-XXXXX.pdf) via eTL. To make an archive file, follow the example below on your own VM. 41 | ``` 42 | $ ls 43 | 2024-12345.pdf Makefile README.md reference src tools 44 | $ tar -cvf 2024-12345.tar src/dirtree.c 2024-12345.pdf 45 | src/dirtree.c 46 | 2024-12345.pdf 47 | $ file 2024-12345.tar 48 | 2024-12345.tar: POSIX tar archive (GNU) 49 | ``` 50 | To move the archive file from VM to your local computer, use either (1) shared folder or (2) scp (secure copy) command. 51 | You can download the archive file from the VM to your local machine with the following commands, which is similar with the ssh command. 52 | 53 | - With VirtualBox: 54 | ```sh 55 | scp -P 8888 sysprog@localhost: 56 | # example: scp -P 8888 sysprog@localhost:/home/sysporg/2024_SPRING_SYSPROG_LAB2/2024-12345.tar . 57 | ``` 58 | 59 | - With UTM: 60 | ```sh 61 | scp sysprog@: 62 | # example: scp sysprog@192.168.4.4:/home/sysprog/2024_SPRING_SYSPROG_LAB2/2024-12345.tar . 63 | ``` 64 | 65 | | parameter | Description | 66 | |:--- |:--- | 67 | | hostname | ip address of VM | 68 | | target_path | absolute path of the file you want to copy (in VM) | 69 | | download_path | (relative) path where a file will be downloaded (in PC) | 70 | 71 | You can get your VM's hostname using `hostname -I` command, and the absolute path of a file using `realpath ` command. 72 | 73 | #### Report Guideline 74 | 75 | Your report should answer following questions. 76 | 77 | 1. Explain `C library call` that you used in your code. 78 | 2. Briefly describe your code including following information 79 | 1. how to iterate through all files in a directory 80 | 2. how to retrieve the metadata of a file 81 | 3. how to print nicely formatted output 82 | 83 | 84 | ## Dirtree Overview 85 | 86 | Our tool is called _dirtree_. Dirtree recursively traverses a directory tree and prints out a sorted list of all files. 87 | 88 | ``` 89 | $ dirtree demo 90 | demo 91 | subdir1 92 | sparsefile 93 | thisisanextremelylongfilenameforsuchasimplisticfile 94 | subdir2 95 | brokenlink 96 | symboliclink 97 | subdir3 98 | pipe 99 | socket 100 | one 101 | two 102 | ``` 103 | 104 | Dirtree can also show details... 105 | ``` 106 | $ dirtree -v demo 107 | demo 108 | subdir1 sysprog:sysprog 4096 rwxrwxr-x d 109 | sparsefile sysprog:sysprog 8192 rw-rw-r-- 110 | thisisanextremelylongfilenameforsuchasimplistic... sysprog:sysprog 1000 rw-rw-r-- 111 | subdir2 sysprog:sysprog 4096 rwxrwxr-x d 112 | brokenlink sysprog:sysprog 8 rwxrwxrwx l 113 | symboliclink sysprog:sysprog 6 rwxrwxrwx l 114 | subdir3 sysprog:sysprog 4096 rwxrwxr-x d 115 | pipe sysprog:sysprog 0 rw-rw-r-- f 116 | socket sysprog:sysprog 0 rwxrwxr-x s 117 | one sysprog:sysprog 1 rw-rw-r-- 118 | two sysprog:sysprog 2 rw-rw-r-- 119 | ``` 120 | 121 | ...or a summary of a directory: 122 | ``` 123 | $ dirtree -v -s demo 124 | Name User:Group Size Perms Type 125 | ---------------------------------------------------------------------------------------------------- 126 | demo 127 | subdir1 sysprog:sysprog 4096 rwxrwxr-x d 128 | sparsefile sysprog:sysprog 8192 rw-rw-r-- 129 | thisisanextremelylongfilenameforsuchasimplistic... sysprog:sysprog 1000 rw-rw-r-- 130 | subdir2 sysprog:sysprog 4096 rwxrwxr-x d 131 | brokenlink sysprog:sysprog 8 rwxrwxrwx l 132 | symboliclink sysprog:sysprog 6 rwxrwxrwx l 133 | subdir3 sysprog:sysprog 4096 rwxrwxr-x d 134 | pipe sysprog:sysprog 0 rw-rw-r-- f 135 | socket sysprog:sysprog 0 rwxrwxr-x s 136 | one sysprog:sysprog 1 rw-rw-r-- 137 | two sysprog:sysprog 2 rw-rw-r-- 138 | ---------------------------------------------------------------------------------------------------- 139 | 4 files, 3 directories, 2 links, 1 pipe, and 1 socket 21497 140 | ``` 141 | 142 | If you want to print directories only, dirtree will. 143 | ``` 144 | $ dirtree -d -v -s demo 145 | Name User:Group Size Perms Type 146 | ---------------------------------------------------------------------------------------------------- 147 | demo 148 | subdir1 sysprog:sysprog 4096 rwxrwxr-x d 149 | subdir2 sysprog:sysprog 4096 rwxrwxr-x d 150 | subdir3 sysprog:sysprog 4096 rwxrwxr-x d 151 | ---------------------------------------------------------------------------------------------------- 152 | 3 directories 153 | ``` 154 | 155 | Last but not least, dirtree can generate aggregate totals over several directories: 156 | ``` 157 | $ dirtree -v -s demo/subdir1 demo/subdir2 158 | Name User:Group Size Perms Type 159 | ---------------------------------------------------------------------------------------------------- 160 | demo/subdir1 161 | sparsefile sysprog:sysprog 8192 rw-rw-r-- 162 | thisisanextremelylongfilenameforsuchasimplisticfile sysprog:sysprog 1000 rw-rw-r-- 163 | ---------------------------------------------------------------------------------------------------- 164 | 2 files, 0 directories, 0 links, 0 pipes, and 0 sockets 9192 165 | 166 | Name User:Group Size Perms Type 167 | ---------------------------------------------------------------------------------------------------- 168 | demo/subdir2 169 | brokenlink sysprog:sysprog 8 rwxrwxrwx l 170 | symboliclink sysprog:sysprog 6 rwxrwxrwx l 171 | ---------------------------------------------------------------------------------------------------- 172 | 0 files, 0 directories, 2 links, 0 pipes, and 0 sockets 14 173 | 174 | Analyzed 2 directories: 175 | total # of files: 2 176 | total # of directories: 0 177 | total # of links: 2 178 | total # of pipes: 0 179 | total # of sockets: 0 180 | total file size: 9206 181 | ``` 182 | 183 | ## Dirtree Specification 184 | 185 | ### Command line arguments 186 | 187 | Dirtree accepts the following command line arguments 188 | ``` 189 | dirtree [Options] [Directories] 190 | ``` 191 | 192 | | Option | Description | 193 | |:---- |:---- | 194 | | -h | Help screen | 195 | | -d | Turn on directory only mode | 196 | | -v | Turn on detailed mode | 197 | | -s | Turn on summary mode | 198 | 199 | `Directories` is a list of directories that are to be traversed. Dirtree accepts up to 64 directories. 200 | If no directory is given, then the current directory is traversed. 201 | 202 | ### Operation 203 | 204 | 1. Dirtree traverses each directory in the list `Directories` recursively. 205 | 2. In each directory, it enumerates all directory entries and prints them in alphabetical order. Directories are listed before files. The special entries '.' and '..' are ignored. 206 | 3. A summary is printed after each directory. If several directories are traversed, an aggregate total is printed at the end. 207 | 208 | ### Output 209 | 210 | As dirtree traverses the directory tree, it prints the names of the sorted entities in a directory. The names are indented according to the level of the subdirectory. For each additional level, the names are printed after two spaces to allow for easy visual identification of the directory structure. 211 | 212 | 213 | 214 | 215 | 218 | 219 | 220 |
216 |
dir             
subdir1
subdir2
file1
file2
file3
file4
217 |
221 | 222 | #### Detailed mode 223 | In detailed mode, dirtree prints out the following additional details for each entry: 224 | * User and group 225 | Each file in Unix belongs to a user and a group. Detailed mode prints the names of the user and the group separated by a colon (:). 226 | * Size 227 | The size of the file in bytes. 228 | * Permissions 229 | The read/write/execute permissions for user owner, for group owner, and for others. 230 | * File type 231 | Indicates the type of file by a single character 232 | 233 | | Type | Character | 234 | |:--- |:---------:| 235 | | File | _(empty)_ | 236 | | Directory | d | 237 | | Link | l | 238 | | Character device | c | 239 | | Block device | b | 240 | | Fifo | f | 241 | | Socket | s | 242 | 243 | 244 | #### Summary mode 245 | In summary mode, dirtree prints a header and footer around each directory and a one-liner containing statistics about the directory. 246 | 247 | If there are more than one directories provided on the command line, an aggregate total of all listed directories is shown. 248 | ``` 249 | $ dirtree -s demo/subdir1 demo/subdir3 250 | 251 | Name 252 | ---------------------------------------------------------------------------------------------------- 253 | demo/subdir1 254 | subdir2 255 | file1 256 | link 257 | ---------------------------------------------------------------------------------------------------- 258 | 1 file, 1 directory, 1 link, 0 pipes, and 0 sockets 259 | 260 | Name 261 | ---------------------------------------------------------------------------------------------------- 262 | demo/subdir3 263 | file2 264 | ---------------------------------------------------------------------------------------------------- 265 | 1 file, 0 directories, 0 links, 0 pipes, and 0 sockets 266 | 267 | Analyzed 2 directories: 268 | total # of files: 2 269 | total # of directories: 1 270 | total # of links: 1 271 | total # of pipes: 0 272 | total # of socksets: 0 273 | ``` 274 | 275 | 276 | #### Directory mode 277 | In directory mode, directory typed entries are printed only. 278 | ``` 279 | $ dirtree -d test1 280 | test1 281 | a 282 | b 283 | c 284 | d 285 | e 286 | dir1 287 | dir2 288 | dir3 289 | ``` 290 | 291 | If summary mode is also enabled, dirtree only counts the number of directories. Any other statistics including size will not be printed in the summary line. 292 | ``` 293 | $ dirtree -d -v -s test1 294 | Name User:Group Size Perms Type 295 | ---------------------------------------------------------------------------------------------------- 296 | test1 297 | a sysprog:sysprog 4096 rwxrwxr-x d 298 | b sysprog:sysprog 4096 rwxrwxr-x d 299 | c sysprog:sysprog 4096 rwxrwxr-x d 300 | d sysprog:sysprog 4096 rwxrwxr-x d 301 | e sysprog:sysprog 4096 rwxrwxr-x d 302 | dir1 sysprog:sysprog 4096 rwxrwxr-x d 303 | dir2 sysprog:sysprog 4096 rwxrwxr-x d 304 | dir3 sysprog:sysprog 4096 rwxrwxr-x d 305 | ---------------------------------------------------------------------------------------------------- 306 | 8 directories 307 | ``` 308 | 309 | 310 | #### Output formatting 311 | The output prints all elements with the correct indentation. 312 | In detailed mode, the output is nicely formatted and filenames that are too long are cut and end with three dots (...). 313 | Unless explicitly specified, you can decide for yourself whether and how you are formatting exceptional cases (error messages, etc.) 314 | 315 | ``` 316 | $ dirtree -v -s demo2 317 | Name User:Group Size Perms Type 318 | ---------------------------------------------------------------------------------------------------- 319 | demo2 320 | subdir1 sysprog:sysprog 4096 rwxrwxr-x d 321 | subdir2 sysprog:sysprog 4096 rwxrwxr-x d 322 | fifo sysprog:sysprog 0 rw-rw-r-- f 323 | link sysprog:sysprog 11 rwxrwxrwx l 324 | socket sysprog:sysprog 0 rwxrwxr-x s 325 | unreasonablyextremelylongfilenamethatdoesntfi... sysprog:sysprog 0 rw-rw-r-- 326 | file4 sysprog:sysprog 0 rw-rw-r-- 327 | ---------------------------------------------------------------------------------------------------- 328 | 2 files, 2 directories, 1 link, 1 pipe, and 1 socket 8203 329 | ``` 330 | 331 | The output in detailed mode consists of the following elements: 332 | 333 | | Output element | Width | Alignment | Action on overflow | 334 | |:--- |:-----:|:---------:|:--- | 335 | | Path and name | 54 | left | cut and end with three dots | 336 | | User name | 8 | right | ignore | 337 | | Group name | 8 | left | ignore | 338 | | File size | 10 | right | ignore | 339 | | Permission | 9 | right | ignore | 340 | | Type | 1 | | | 341 | | Summary line | 68 | left | limit to 68 characters | 342 | | Total size | 14 | right | ignore | 343 | 344 | The following rendering shows the output formatting in detail for each of the different elements. The two rows on top indicate the character position on a line. 345 | ``` 346 | 1 2 3 4 5 6 7 8 9 10 347 | 1........0.........0.........0.........0.........0.........0.........0.........0.........0.........0 348 | 349 | Name User:Group Size Perms Type 350 | ---------------------------------------------------------------------------------------------------- 351 | < user>: < size> < perms> t 352 | < user>: < size> < perms> t 353 | ... 354 | ---------------------------------------------------------------------------------------------------- 355 | < total size> 356 | ``` 357 | 358 | ##### Summary line 359 | dirtree takes great care to output grammatically correct English. Zero or >=2 elements are output in plural form, while for exactly one element the singular form is used. 360 | Compare the two summary lines: 361 | ``` 362 | 0 files, 2 directories, 1 link, 1 pipe, and 1 socket 363 | 364 | 1 file, 1 directory, 2 links, 0 pipes, and 5 sockets 365 | ``` 366 | 367 | ### Error handling 368 | 369 | Errors that occur when processing a directory are reported in place of the entries of that directory: 370 | ``` 371 | $ dirtree -v /etc/cups 372 | /etc/cups 373 | ... 374 | interfaces root:lp 4096 rwxr-xr-x d 375 | ppd root:lp 4096 rwxr-xr-x d 376 | .keep_net-print_cups-0 root:root 0 rw-r--r-- 377 | ssl root:lp 4096 rwx------ d 378 | ERROR: Permission denied 379 | client.conf root:root 31 rw-r--r-- 380 | ... 381 | ``` 382 | This kind of error has the message format `ERROR: ` and it should be printed after the indentation as before. 383 | 384 | 385 | If an error occurs when retrieving the meta data of a file, the error message is printed inplace of the file's meta data: 386 | ``` 387 | $ dirtree -v -s demo3 388 | Name User:Group Size Perms Type 389 | ---------------------------------------------------------------------------------------------------- 390 | demo3 391 | dir1 sysprog:sysprog 4096 --x------ d 392 | ERROR: Permission denied 393 | dir2 sysprog:sysprog 4096 r-------- d 394 | file1 Permission denied 395 | file2 Permission denied 396 | file3 Permission denied 397 | dir3 sysprog:sysprog 4096 rwx------ d 398 | file4 sysprog:sysprog 0 -----x--- 399 | file5 sysprog:sysprog 0 ----w---- 400 | file6 sysprog:sysprog 0 ---r----- 401 | ---------------------------------------------------------------------------------------------------- 402 | 6 files, 3 directories, 0 links, 0 pipes, and 0 sockets 12288 403 | ``` 404 | In this case, the message starts two spaces after the `path and name` element with left alignment. 405 | 406 | For any other errors, you can choose what to do. The reference implementation aborts on most errors: 407 | ``` 408 | $ dirtree -v /proc/self/fd 409 | /proc/self/fd 410 | 0 sysprog:sysprog 64 rwx------ l 411 | 1 sysprog:sysprog 64 rwx------ l 412 | 2 sysprog:sysprog 64 rwx------ l 413 | 3 No such file or directory 414 | ``` 415 | ``` 416 | $ dirtree -s -v demo 417 | Name User:Group Size Perms Type 418 | ---------------------------------------------------------------------------------------------------- 419 | demo 420 | subdir1 arcuser:users 4096 rwxrwxr-x d 421 | sparsefile arcuser:users 8192 rw-rw-r-- 422 | Out of memory. 423 | ``` 424 | 425 | ## Handout Overview 426 | 427 | The handout contains the following files and directories 428 | 429 | | File/Directory | Description | 430 | |:--- |:--- | 431 | | README.md | this file | 432 | | Makefile | Makefile driver program | 433 | | src/dirtree.c | Skeleton for dirtree.c. Implement your solution by editing this file. | 434 | | reference/ | Reference implementation | 435 | | tools/ | Tools to generate directory trees for testing | 436 | 437 | ### Reference implementation 438 | 439 | The directory `reference` contains our reference implementation. You can use it to compare your output to ours. 440 | 441 | ### Tools 442 | 443 | The `tools` directory contains tools to generate test directory trees to test your solution. 444 | 445 | | File/Directory | Description | 446 | |:--- |:--- | 447 | | gentree.sh | Driver script to generate a test directory tree. | 448 | | mksock | Helper script to generate a Unix socket. | 449 | | *.tree | Script files describing the directory tree layout. | 450 | 451 | Invoke `gentree.sh` with a script file to generate one of the provided test directory trees. 452 | 453 | **Note:** due to limitations of VirtualBox's shared folder implementation and your host OS, not all file types are supported in the shared folder. We recommand to create the test directories natively inside the VM, for example, in the `work/` directory. 454 | 455 | Assuming you are located in the root directory of your I/O lab repository, use the follwing command to generate the `demo` directory tree 456 | ```bash 457 | $ ls 458 | dirtree.c Makefile README.md reference tools 459 | $ tools/gentree.sh tools/demo.tree 460 | Generating tree from 'tools/demo.tree'... 461 | Done. Generated 4 files, 2 links, 1 fifos, and 1 sockets. 0 errors reported. 462 | ``` 463 | 464 | You can list the contents of the tree with the reference implementation: 465 | ```bash 466 | $ reference/dirtree -v -s demo/ 467 | Name User:Group Size Perms Type 468 | ---------------------------------------------------------------------------------------------------- 469 | demo/ 470 | subdir1 sysprog:sysprog 4096 rwxrwxr-x d 471 | sparsefile sysprog:sysprog 8192 rw-rw-r-- 472 | thisisanextremelylongfilenameforsuchasimplistic... sysprog:sysprog 1000 rw-rw-r-- 473 | subdir2 sysprog:sysprog 4096 rwxrwxr-x d 474 | brokenlink sysprog:sysprog 8 rwxrwxrwx l 475 | symboliclink sysprog:sysprog 6 rwxrwxrwx l 476 | subdir3 sysprog:sysprog 4096 rwxrwxr-x d 477 | pipe sysprog:sysprog 0 rw-rw-r-- f 478 | socket sysprog:sysprog 0 rwxrwxr-x s 479 | one sysprog:sysprog 1 rw-rw-r-- 480 | two sysprog:sysprog 2 rw-rw-r-- 481 | ---------------------------------------------------------------------------------------------------- 482 | 4 files, 3 directories, 2 links, 1 pipe, and 1 socket 21497 483 | ``` 484 | 485 | 486 | ## Your Task 487 | 488 | Your task is to implement dirtree according to the specification above. 489 | 490 | ### Design 491 | 492 | In a first step, write down the logical steps of your program on a sheet of paper. We will do that together during the first lab session. 493 | 494 | **Recommendation**: do not look at the provided code in `dirtree.c` yet! Think about the logical steps yourself. 495 | The design is the most difficult and important phase in any project - and also the phase that requires the most practice and sets apart hobby programmers from experts. 496 | 497 | ### Implementation 498 | 499 | Once you have designed the outline of your implementation, you can start implementing it. We provide a skeleton file to help you get started. 500 | 501 | The skeleton provides data structures to manage the statistics of a directory, a function to read the next entry from a directory while ignoring the '.' and '..' entries, a comparator function to sort the entries of a directory using quicksort, and full argument parsing and syntax helpers. 502 | 503 | You have to implement the following two parts: 504 | 1. in `main()` 505 | Iterate through the list of directories stored in `directories`. For each directory, call `processDir()` with the appropriate parameters. Also, depending on the output mode, print header, footer, and statistics. 506 | 2. in `processDir()` 507 | Open, enumerate, sort, and close the directory. Print elements one by one. Update statistics. If the element is a directory, call `processDir()` recursively. 508 | 509 | ### Hints 510 | 511 | #### Skeleton code 512 | The skeleton code is meant to help you get started. You can modify it in any way you see fit - or implement this lab completely from scratch. 513 | 514 | #### C library calls 515 | 516 | Knowing which library functions exist and how to use them is difficult at the beginning in every programming language. To help you get started, we provide a list of C library calls / system calls grouped by topic that you may find helpful to solve this lab. Read the man pages carefully to learn how exactly the functions operate. 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 531 | 534 | 537 | 538 | 539 | 542 | 545 | 546 | 547 | 550 | 553 | 554 | 555 | 558 | 562 | 563 | 564 | 567 | 570 | 573 | 574 | 575 | 578 | 581 | 582 | 583 | 586 | 589 | 590 | 591 | 594 | 597 | 600 | 601 | 602 | 605 | 608 | 609 | 610 | 613 | 616 | 619 | 620 | 621 | 624 | 627 | 628 | 629 | 632 | 635 | 638 | 639 | 640 | 643 | 646 | 650 | 651 | 652 |
TopicC library callDescription
529 | String operations 530 | 532 | strcmp() 533 | 535 | compare two strings 536 |
540 | strncpy() 541 | 543 | copy up to n characters of one string into another 544 |
548 | strdup() 549 | 551 | create a copy of a string. Use free() to free it after use 552 |
556 | asprintf() 557 | 559 | asprintf() is extremely helpful to print into a string and allocate memory for it at the same time. 560 | We will show some examples during the lab session. 561 |
565 | Directory management 566 | 568 | opendir() 569 | 571 | open a directory to enumerate its entries 572 |
576 | closedir() 577 | 579 | close an open directory 580 |
584 | readdir() 585 | 587 | read next entry from directory 588 |
592 | File meta data 593 | 595 | stat() 596 | 598 | retrieve meta data of a file, follow links 599 |
603 | lstat() 604 | 606 | retrieve meta data of a file, do not follow links 607 |
611 | User/group information 612 | 614 | getpwuid() 615 | 617 | retrieve user information (including their name) for a given user ID 618 |
622 | getgrgid() 623 | 625 | retrieve group information (including its name) for a given group ID 626 |
630 | Sorting 631 | 633 | qsort() 634 | 636 | quick-sort an array 637 |
641 | Error Handling 642 | 644 | strerror() 645 | 647 | Get string pointer for given error code.
648 | Refer errno man page for detailed error code description. 649 |
653 | 654 | #### Final words 655 | 656 | This may well be your first project interacting with the C standard library and system calls. At the beginning, you may feel overwhelmed and have no idea how to approach this task. 657 | 658 | Do not despair - we will give detailed instructions during the lab sessions and provide individual help so that each of you can finish this lab. After completing this lab, you can call yourself a system programmer. Inexperienced still, but anyway a system programmer. 659 | 660 |
661 | 662 | **Happy coding!** 663 |
664 | -------------------------------------------------------------------------------- /reference/dirtree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SNU-ARC/2024_spring_sysprog_Lab2/81c0ed2a9a3ffef93610deae965386fef17c3ffa/reference/dirtree -------------------------------------------------------------------------------- /src/dirtree.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------------------- 2 | // System Programming I/O Lab Spring 2024 3 | // 4 | /// @file 5 | /// @brief resursively traverse directory tree and list all entries 6 | /// @author 7 | /// @studid 8 | //-------------------------------------------------------------------------------------------------- 9 | 10 | #define _GNU_SOURCE 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define MAX_DIR 64 ///< maximum number of supported directories 25 | 26 | /// @brief output control flags 27 | #define F_DIRONLY 0x1 ///< turn on direcetory only option 28 | #define F_SUMMARY 0x2 ///< enable summary 29 | #define F_VERBOSE 0x4 ///< turn on verbose mode 30 | 31 | /// @brief struct holding the summary 32 | struct summary { 33 | unsigned int dirs; ///< number of directories encountered 34 | unsigned int files; ///< number of files 35 | unsigned int links; ///< number of links 36 | unsigned int fifos; ///< number of pipes 37 | unsigned int socks; ///< number of sockets 38 | 39 | unsigned long long size; ///< total size (in bytes) 40 | }; 41 | 42 | 43 | /// @brief abort the program with EXIT_FAILURE and an optional error message 44 | /// 45 | /// @param msg optional error message or NULL 46 | void panic(const char *msg) 47 | { 48 | if (msg) fprintf(stderr, "%s\n", msg); 49 | exit(EXIT_FAILURE); 50 | } 51 | 52 | 53 | /// @brief read next directory entry from open directory 'dir'. Ignores '.' and '..' entries 54 | /// 55 | /// @param dir open DIR* stream 56 | /// @retval entry on success 57 | /// @retval NULL on error or if there are no more entries 58 | struct dirent *getNext(DIR *dir) 59 | { 60 | struct dirent *next; 61 | int ignore; 62 | 63 | do { 64 | errno = 0; 65 | next = readdir(dir); 66 | if (errno != 0) perror(NULL); 67 | ignore = next && ((strcmp(next->d_name, ".") == 0) || (strcmp(next->d_name, "..") == 0)); 68 | } while (next && ignore); 69 | 70 | return next; 71 | } 72 | 73 | 74 | /// @brief qsort comparator to sort directory entries. Sorted by name, directories first. 75 | /// 76 | /// @param a pointer to first entry 77 | /// @param b pointer to second entry 78 | /// @retval -1 if ab 81 | static int dirent_compare(const void *a, const void *b) 82 | { 83 | struct dirent *e1 = (struct dirent*)a; 84 | struct dirent *e2 = (struct dirent*)b; 85 | 86 | // if one of the entries is a directory, it comes first 87 | if (e1->d_type != e2->d_type) { 88 | if (e1->d_type == DT_DIR) return -1; 89 | if (e2->d_type == DT_DIR) return 1; 90 | } 91 | 92 | // otherwise sorty by name 93 | return strcmp(e1->d_name, e2->d_name); 94 | } 95 | 96 | 97 | /// @brief recursively process directory @a dn and print its tree 98 | /// 99 | /// @param dn absolute or relative path string 100 | /// @param depth depth in directory tree 101 | /// @param stats pointer to statistics 102 | /// @param flags output control flags (F_*) 103 | void processDir(const char *dn, unsigned int depth, struct summary *stats, unsigned int flags) 104 | { 105 | // TODO 106 | } 107 | 108 | 109 | /// @brief print program syntax and an optional error message. Aborts the program with EXIT_FAILURE 110 | /// 111 | /// @param argv0 command line argument 0 (executable) 112 | /// @param error optional error (format) string (printf format) or NULL 113 | /// @param ... parameter to the error format string 114 | void syntax(const char *argv0, const char *error, ...) 115 | { 116 | if (error) { 117 | va_list ap; 118 | 119 | va_start(ap, error); 120 | vfprintf(stderr, error, ap); 121 | va_end(ap); 122 | 123 | printf("\n\n"); 124 | } 125 | 126 | assert(argv0 != NULL); 127 | 128 | fprintf(stderr, "Usage %s [-d] [-s] [-v] [-h] [path...]\n" 129 | "Gather information about directory trees. If no path is given, the current directory\n" 130 | "is analyzed.\n" 131 | "\n" 132 | "Options:\n" 133 | " -d print directories only\n" 134 | " -s print summary of directories (total number of files, total file size, etc)\n" 135 | " -v print detailed information for each file. Turns on tree view.\n" 136 | " -h print this help\n" 137 | " path... list of space-separated paths (max %d). Default is the current directory.\n", 138 | basename(argv0), MAX_DIR); 139 | 140 | exit(EXIT_FAILURE); 141 | } 142 | 143 | 144 | /// @brief program entry point 145 | int main(int argc, char *argv[]) 146 | { 147 | // 148 | // default directory is the current directory (".") 149 | // 150 | const char CURDIR[] = "."; 151 | const char *directories[MAX_DIR]; 152 | int ndir = 0; 153 | 154 | struct summary tstat; 155 | unsigned int flags = 0; 156 | 157 | // 158 | // parse arguments 159 | // 160 | for (int i = 1; i < argc; i++) { 161 | if (argv[i][0] == '-') { 162 | // format: "-" 163 | if (!strcmp(argv[i], "-d")) flags |= F_DIRONLY; 164 | else if (!strcmp(argv[i], "-s")) flags |= F_SUMMARY; 165 | else if (!strcmp(argv[i], "-v")) flags |= F_VERBOSE; 166 | else if (!strcmp(argv[i], "-h")) syntax(argv[0], NULL); 167 | else syntax(argv[0], "Unrecognized option '%s'.", argv[i]); 168 | } else { 169 | // anything else is recognized as a directory 170 | if (ndir < MAX_DIR) { 171 | directories[ndir++] = argv[i]; 172 | } else { 173 | printf("Warning: maximum number of directories exceeded, ignoring '%s'.\n", argv[i]); 174 | } 175 | } 176 | } 177 | 178 | // if no directory was specified, use the current directory 179 | if (ndir == 0) directories[ndir++] = CURDIR; 180 | 181 | 182 | // 183 | // process each directory 184 | // 185 | // TODO 186 | // 187 | // Pseudo-code 188 | // - reset statistics (tstat) 189 | // - loop over all entries in 'directories' (number of entires stored in 'ndir') 190 | // - reset statistics (dstat) 191 | // - if F_SUMMARY flag set: print header 192 | // - print directory name 193 | // - call processDir() for the directory 194 | // - if F_SUMMARY flag set: print summary & update statistics 195 | memset(&tstat, 0, sizeof(tstat)); 196 | //... 197 | 198 | 199 | // 200 | // print grand total 201 | // 202 | if ((flags & F_SUMMARY) && (ndir > 1)) { 203 | if (flags & F_DIRONLY) { 204 | printf("Analyzed %d directories:\n" 205 | " total # of directories: %16d\n", 206 | ndir, tstat.dirs); 207 | } else { 208 | printf("Analyzed %d directories:\n" 209 | " total # of files: %16d\n" 210 | " total # of directories: %16d\n" 211 | " total # of links: %16d\n" 212 | " total # of pipes: %16d\n" 213 | " total # of sockets: %16d\n", 214 | ndir, tstat.files, tstat.dirs, tstat.links, tstat.fifos, tstat.socks); 215 | 216 | if (flags & F_VERBOSE) { 217 | printf(" total file size: %16llu\n", tstat.size); 218 | } 219 | } 220 | } 221 | 222 | // 223 | // that's all, folks! 224 | // 225 | return EXIT_SUCCESS; 226 | } 227 | -------------------------------------------------------------------------------- /tools/demo.tree: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------------------------- 2 | # System Programming I/O Lab Spring 2024 3 | # 4 | # demo directory tree 5 | # 6 | f ./demo/one 1 0 7 | f ./demo/two 2 0 8 | f ./demo/subdir1/thisisanextremelylongfilenameforsuchasimplisticfile 1000 0 9 | f ./demo/subdir1/sparsefile 4096 4096 10 | l ./demo/subdir2/symboliclink ./demo/two 11 | l ./demo/subdir2/brokenlink ./demo/three 12 | p ./demo/subdir3/pipe 13 | s ./demo/subdir3/socket 14 | -------------------------------------------------------------------------------- /tools/gentree.sh: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------------------------- 2 | # System Programming I/O Lab Spring 2024 3 | # 4 | # script to generate directory tree for testing 5 | # 6 | # Author: Bernhard Egger 7 | # 8 | 9 | INPUT=${0%/*}/test1.tree 10 | MKSOCK= 11 | 12 | if [[ -n "$1" ]]; then 13 | INPUT=$1 14 | fi 15 | 16 | if [[ ! -r $INPUT ]]; then 17 | echo "Cannot read from input file '$INPUT'." 18 | exit 1 19 | fi 20 | 21 | LINEC=0 22 | FILES=0 23 | LINKS=0 24 | PIPES=0 25 | SOCKS=0 26 | 27 | echo "Generating tree from '$INPUT'..." 28 | while read line; do 29 | # ignore comments 30 | [[ $line =~ ^#.* ]] && continue 31 | 32 | # split and ignore blank lines 33 | read -a split <<< "$line" 34 | [[ ${#split[*]} == 0 ]] && continue 35 | 36 | tokens=${#split[*]} 37 | 38 | let LINEC=$LINEC+1 39 | 40 | case ${split[0],,} in 41 | f) # regular file 42 | # [[ ${#split[*]} != 4 ]] && echo " Ingoring invalid file spec '$line'." && continue 43 | [[ ${tokens} < 4 || ${tokens} > 5 ]] && echo " Ingoring invalid file spec '$line'." && continue 44 | MOD=${split[4]} 45 | [[ ${tokens} == 4 ]] && MOD=664 46 | 47 | file=${split[1]} 48 | size=${split[2]} 49 | skip=${split[3]} 50 | 51 | mkdir -p ${file%/*} && dd if=/dev/zero of=$file bs=1 count=$size seek=$skip 2>/dev/null 52 | if [[ $? == 0 ]]; then 53 | let FILES=$FILES+1 54 | else 55 | echo " Failed to create file '$file'." 56 | fi 57 | 58 | chmod $MOD $file 59 | 60 | ;; 61 | 62 | l) # symbolic link 63 | [[ ${#split[*]} != 3 ]] && echo " Ingoring invalid link spec '$line'." && continue 64 | 65 | from=${split[1]} 66 | to=${split[2]} 67 | 68 | mkdir -p ${from%/*} && ln -srf $to $from 69 | if [[ $? == 0 ]]; then 70 | let LINKS=$LINKS+1 71 | else 72 | echo " Failed to create link '$from'." 73 | fi 74 | 75 | ;; 76 | 77 | p) # named pipe 78 | [[ ${#split[*]} != 2 ]] && echo " Ingoring invalid fifo spec '$line'." && continue 79 | 80 | fifo=${split[1]} 81 | 82 | mkdir -p ${fifo%/*} && mkfifo $fifo 2>/dev/null 83 | if [[ $? == 0 ]]; then 84 | let PIPES=$PIPES+1 85 | else 86 | echo " Failed to create named pipe '$fifo'." 87 | fi 88 | 89 | ;; 90 | 91 | s) # unix socket 92 | [[ ${#split[*]} != 2 ]] && echo " Ingoring invalid socket spec '$line'." && continue 93 | 94 | if [[ -z "$MKSOCK" ]]; then 95 | MKSOCK=`PATH=${0%/*}:$PATH which mksock 2>/dev/null` 96 | [[ ! -x "$MKSOCK" ]] && echo " Can't find 'mksock', ignoring socket." && continue 97 | fi 98 | 99 | socket=${split[1]} 100 | 101 | mkdir -p ${socket%/*} && $MKSOCK $socket 2>/dev/null 102 | if [[ $? == 0 ]]; then 103 | let SOCKS=$SOCKS+1 104 | else 105 | echo " Failed to create unix socket '$socket'." 106 | fi 107 | 108 | ;; 109 | 110 | *) # unknown 111 | echo " Ingoring invalid line: '$line'." 112 | ;; 113 | esac 114 | 115 | done < <(cat $INPUT) 116 | 117 | let ERRORS=$LINEC-$FILES-$LINKS-$PIPES-$SOCKS 118 | echo "Done. Generated $FILES files, $LINKS links, $PIPES fifos, and $SOCKS sockets. $ERRORS errors reported." 119 | 120 | exit 0 121 | 122 | 123 | -------------------------------------------------------------------------------- /tools/mksock: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -c "import socket as s; sock = s.socket(s.AF_UNIX); sock.bind('$1')" 3 | 4 | -------------------------------------------------------------------------------- /tools/test1.tree: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------------------------- 2 | # System Programming I/O Lab Spring 2024 3 | # 4 | # test directory tree 1 5 | # 6 | f ./test1/one 1 0 7 | f ./test1/two 2 0 644 8 | f ./test1/three 3 0 9 | f ./test1/four 4 0 10 | f ./test1/five 5 0 11 | f ./test1/executable 100 0 755 12 | f ./test1/dir3/six 6 0 13 | f ./test1/dir3/seven 7 0 14 | f ./test1/dir3/eight 8 0 15 | f ./test1/dir3/nine 9 0 16 | f ./test1/dir3/ten 10 0 17 | f ./test1/dir2/six 6 0 18 | f ./test1/dir2/seven 7 0 19 | f ./test1/dir2/eight 8 0 20 | f ./test1/dir2/nine 9 0 21 | f ./test1/dir2/ten 10 0 22 | f ./test1/dir1/bothfilenameand.extensionarelong 100 0 23 | f ./test1/a/b/c/d/e/f 0 0 24 | f ./test1/a/b/f 0 0 25 | -------------------------------------------------------------------------------- /tools/test2.tree: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------------------------- 2 | # System Programming I/O Lab Spring 2024 3 | # 4 | # test directory tree 2 5 | # 6 | f ./test2/one 1 0 7 | f ./test2/two 2 0 8 | f ./test2/three 3 0 9 | f ./test2/four 4 0 10 | f ./test2/five 5 0 11 | l ./test2/six ./test2/five 12 | l ./test2/seven ./test2/six 13 | f ./test2/subdir1/target 0 0 14 | l ./test2/subdir2/link ./test2/subdir1/target 15 | -------------------------------------------------------------------------------- /tools/test3.tree: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------------------------- 2 | # System Programming I/O Lab Spring 2024 3 | # 4 | # test directory tree 3 5 | # 6 | f ./test3/one 1 0 7 | f ./test3/two 2 0 8 | f ./test3/three 3 0 9 | f ./test3/four 4 0 10 | f ./test3/five 5 0 11 | l ./test3/subdir1/link ./test3/five 12 | l ./test3/subdir1/root /root 13 | p ./test3/subdir1/pipe 14 | s ./test3/subdir1/socket 15 | --------------------------------------------------------------------------------