static bool archive_file (char file_name[], size_t file_name_size, int archive_fd, bool *write_error) { int file_fd = open (file_name); if (file_fd >= 0) { bool success; if (inumber (file_fd) != inumber (archive_fd)) { if (!isdir (file_fd)) success = archive_ordinary_file (file_name, file_fd, archive_fd, write_error); else success = archive_directory (file_name, file_name_size, file_fd, archive_fd, write_error); } else { /* Nothing to do: don't try to archive the archive file. */ success = true; } close (file_fd); return success; } else { printf ("%s: open failed\n", file_name); return false; } }
static bool list_dir (const char *dir, bool verbose) { int dir_fd = open (dir); if (dir_fd == -1) { printf ("%s: not found\n", dir); return false; } if (isdir (dir_fd)) { char name[READDIR_MAX_LEN]; printf ("%s", dir); if (verbose) printf (" (inumber %d)", inumber (dir_fd)); printf (":\n"); while (readdir (dir_fd, name)) { printf ("%s", name); if (verbose) { char full_name[128]; int entry_fd; snprintf (full_name, sizeof full_name, "%s/%s", dir, name); entry_fd = open (full_name); printf (": "); if (entry_fd != -1) { if (isdir (entry_fd)) printf ("directory"); else printf ("%d-byte file", filesize (entry_fd)); printf (", inumber %d", inumber (entry_fd)); } else printf ("open failed"); close (entry_fd); } printf ("\n"); } } else printf ("%s: not a directory\n", dir); close (dir_fd); return true; }
void test_main (void) { int root_fd, a_fd0; char name[READDIR_MAX_LEN + 1]; root_fd = wrap_open ("/"); CHECK (mkdir ("a"), "mkdir \"a\""); a_fd0 = wrap_open ("/a"); CHECK (!readdir (a_fd0, name), "verify \"/a\" is empty"); CHECK (inumber (root_fd) != inumber (a_fd0), "\"/\" and \"/a\" must have different inumbers"); CHECK (chdir ("a"), "chdir \"a\""); msg ("try to remove \"/a\""); if (remove ("/a")) { msg ("remove successful"); CHECK (open ("/a") == -1, "open \"/a\" (must fail)"); CHECK (open (".") == -1, "open \".\" (must fail)"); CHECK (open ("..") == -1, "open \"..\" (must fail)"); CHECK (!create ("x", 512), "create \"x\" (must fail)"); } else { int a_fd1, a_fd2, a_fd3; msg ("remove failed"); CHECK (!remove ("../a"), "try to remove \"../a\" (must fail)"); CHECK (!remove (".././a"), "try to remove \".././a\" (must fail)"); CHECK (!remove ("/./a"), "try to remove \"/./a\" (must fail)"); a_fd1 = wrap_open ("/a"); a_fd2 = wrap_open ("."); CHECK (inumber (a_fd1) == inumber (a_fd2), "\"/a\" and \".\" must have same inumber"); CHECK (inumber (root_fd) != inumber (a_fd1), "\"/\" and \"/a\" must have different inumbers"); CHECK (chdir ("/a"), "chdir \"/a\""); a_fd3 = wrap_open ("."); CHECK (inumber (a_fd3) == inumber (a_fd1), "\".\" must have same inumber as before"); CHECK (chdir ("/"), "chdir \"/\""); CHECK (!remove ("a"), "try to remove \"a\" (must fail: still open)"); } CHECK (!readdir (a_fd0, name), "verify \"/a\" is empty"); }
/* Stores the inode number for FILE_NAME in *INUM. Returns true if successful, false if the file could not be opened. */ static bool get_inumber (const char *file_name, int *inum) { int fd = open (file_name); if (fd >= 0) { *inum = inumber (fd); close (fd); return true; } else return false; }
/* Stores the current working directory, as a null-terminated string, in the CWD_SIZE bytes in CWD. Returns true if successful, false on error. Errors include system errors, directory trees deeper than MAX_LEVEL levels, and insufficient space in CWD. */ static bool getcwd (char *cwd, size_t cwd_size) { size_t cwd_len = 0; #define MAX_LEVEL 20 char name[MAX_LEVEL * 3 + 1 + READDIR_MAX_LEN + 1]; char *namep; int child_inum; /* Make sure there's enough space for at least "/". */ if (cwd_size < 2) return false; /* Get inumber for current directory. */ if (!get_inumber (".", &child_inum)) return false; namep = name; for (;;) { int parent_inum, parent_fd; /* Compose "../../../..", etc., in NAME. */ if ((namep - name) > MAX_LEVEL * 3) return false; *namep++ = '.'; *namep++ = '.'; *namep = '\0'; /* Open directory. */ parent_fd = open (name); if (parent_fd < 0) return false; *namep++ = '/'; /* If parent and child have the same inumber, then we've arrived at the root. */ parent_inum = inumber (parent_fd); if (parent_inum == child_inum) break; /* Find name of file in parent directory with the child's inumber. */ for (;;) { int test_inum; if (!readdir (parent_fd, namep) || !get_inumber (name, &test_inum)) { close (parent_fd); return false; } if (test_inum == child_inum) break; } close (parent_fd); /* Prepend "/name" to CWD. */ if (!prepend (namep - 1, cwd, &cwd_len, cwd_size)) return false; /* Move up. */ child_inum = parent_inum; } /* Finalize CWD. */ if (cwd_len > 0) { /* Move the string to the beginning of CWD, and null-terminate it. */ memmove (cwd, (cwd + cwd_size) - cwd_len, cwd_len); cwd[cwd_len] = '\0'; } else { /* Special case for the root. */ strlcpy (cwd, "/", cwd_size); } return true; }