1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
| #define _GNU_SOURCE // 启用 GNU 扩展 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> // 包含 stat, lstat #include <fcntl.h> // 包含 open, O_* flags #include <string.h> #include <errno.h> #include <libgen.h> // 包含 dirname, basename
// 辅助函数:打印文件信息 void print_file_info(const char *path, const char* description) { struct stat sb; printf("--- %s: %s ---\n", description, path);
// 使用 lstat 获取符号链接本身的信息 if (lstat(path, &sb) == -1) { perror("lstat"); return; }
printf(" Inode: %ld\n", (long) sb.st_ino); printf(" Links: %ld\n", (long) sb.st_nlink); printf(" Size: %ld bytes\n", (long) sb.st_size);
if (S_ISLNK(sb.st_mode)) { printf(" Type: Symbolic Link\n"); // 读取符号链接指向的目标 char target_path[1024]; ssize_t len = readlink(path, target_path, sizeof(target_path) - 1); if (len != -1) { target_path[len] = '\0'; printf(" -> Points to: %s\n", target_path); } else { perror("readlink"); } } else if (S_ISREG(sb.st_mode)) { printf(" Type: Regular File\n"); } else if (S_ISDIR(sb.st_mode)) { printf(" Type: Directory\n"); } else { printf(" Type: Other (Mode: %o)\n", sb.st_mode & S_IFMT); } printf("\n"); }
int main() { const char *original_file = "original_file.txt"; const char *hard_link = "hard_link_to_original.txt"; const char *sym_link_absolute = "symlink_absolute_to_original.txt"; const char *sym_link_relative = "symlink_relative_to_original.txt"; const char *sym_link_dangling = "symlink_to_nonexistent.txt"; const char *test_dir = "test_symlink_dir"; const char *sym_link_in_dir = "symlink_in_dir.txt"; int dirfd;
printf("--- Demonstrating symlink and symlinkat ---\n");
// 1. 创建一个原始文件 FILE *f = fopen(original_file, "w"); if (!f) { perror("fopen original_file.txt"); exit(EXIT_FAILURE); } fprintf(f, "This is the content of the original file.\n"); fclose(f); printf("Created original file: %s\n", original_file);
// 2. 创建硬链接 if (link(original_file, hard_link) == -1) { perror("link"); // 清理并退出 unlink(original_file); exit(EXIT_FAILURE); } printf("Created hard link: %s -> %s\n", hard_link, original_file);
// 3. 创建符号链接 (绝对路径) // 注意:target 是字符串,不一定需要存在 if (symlink("/full/path/to/somewhere", sym_link_absolute) == -1) { perror("symlink absolute"); // 清理并退出 unlink(original_file); unlink(hard_link); exit(EXIT_FAILURE); } printf("Created symbolic link (absolute target): %s -> /full/path/to/somewhere\n", sym_link_absolute);
// 4. 创建符号链接 (相对路径) if (symlink(original_file, sym_link_relative) == -1) { perror("symlink relative"); // 清理并退出 unlink(original_file); unlink(hard_link); unlink(sym_link_absolute); exit(EXIT_FAILURE); } printf("Created symbolic link (relative target): %s -> %s\n", sym_link_relative, original_file);
// 5. 创建一个指向不存在文件的符号链接 (悬空链接) if (symlink("this_file_does_not_exist.txt", sym_link_dangling) == -1) { perror("symlink dangling"); // 清理并退出 unlink(original_file); unlink(hard_link); unlink(sym_link_absolute); unlink(sym_link_relative); exit(EXIT_FAILURE); } printf("Created dangling symbolic link: %s -> this_file_does_not_exist.txt\n", sym_link_dangling);
// 6. 演示 symlinkat // 首先创建一个目录 if (mkdir(test_dir, 0755) == -1 && errno != EEXIST) { perror("mkdir test_symlink_dir"); // 清理并退出 unlink(original_file); unlink(hard_link); unlink(sym_link_absolute); unlink(sym_link_relative); unlink(sym_link_dangling); exit(EXIT_FAILURE); } printf("\nCreated directory: %s\n", test_dir);
// 打开目录以获取文件描述符 dirfd = open(test_dir, O_RDONLY | O_DIRECTORY); if (dirfd == -1) { perror("open test_symlink_dir"); // 清理并退出 unlink(original_file); unlink(hard_link); unlink(sym_link_absolute); unlink(sym_link_relative); unlink(sym_link_dangling); rmdir(test_dir); exit(EXIT_FAILURE); }
// 使用 symlinkat 在目录中创建符号链接 // linkpath 是相对路径 "symlink_in_dir.txt",它相对于 dirfd (test_symlink_dir) 解析 // target 是 "../original_file.txt",这是符号链接存储的内容 if (symlinkat("../original_file.txt", dirfd, sym_link_in_dir) == -1) { perror("symlinkat"); close(dirfd); // 清理并退出 unlink(original_file); unlink(hard_link); unlink(sym_link_absolute); unlink(sym_link_relative); unlink(sym_link_dangling); rmdir(test_dir); exit(EXIT_FAILURE); } printf("Created symbolic link using symlinkat: %s/%s -> ../original_file.txt\n", test_dir, sym_link_in_dir); close(dirfd);
// 7. 检查所有创建的文件/链接的信息 printf("\n--- File Information ---\n"); print_file_info(original_file, "Original File"); print_file_info(hard_link, "Hard Link"); print_file_info(sym_link_absolute, "Symbolic Link (Absolute)"); print_file_info(sym_link_relative, "Symbolic Link (Relative)"); print_file_info(sym_link_dangling, "Dangling Symbolic Link"); char full_sym_link_in_dir[512]; snprintf(full_sym_link_in_dir, sizeof(full_sym_link_in_dir), "%s/%s", test_dir, sym_link_in_dir); print_file_info(full_sym_link_in_dir, "Symbolic Link (Created with symlinkat)");
// 8. 演示访问符号链接 printf("--- Accessing Files ---\n"); // 访问原始文件 if (access(original_file, F_OK) == 0) { printf("Can access original file '%s'.\n", original_file); } // 访问硬链接 (效果同原始文件) if (access(hard_link, F_OK) == 0) { printf("Can access hard link '%s'.\n", hard_link); } // 访问相对符号链接 (应该成功,指向存在的文件) if (access(sym_link_relative, F_OK) == 0) { printf("Can access symbolic link '%s' (follows to existing target).\n", sym_link_relative); } else { printf("Cannot access symbolic link '%s': %s\n", sym_link_relative, strerror(errno)); } // 访问悬空符号链接 (会失败) if (access(sym_link_dangling, F_OK) == 0) { printf("Can access dangling symbolic link '%s' (unexpected).\n", sym_link_dangling); } else { printf("Cannot access dangling symbolic link '%s': %s (expected)\n", sym_link_dangling, strerror(errno)); }
// 9. 清理创建的文件和目录 printf("\n--- Cleaning Up ---\n"); unlink(original_file); unlink(hard_link); unlink(sym_link_absolute); unlink(sym_link_relative); unlink(sym_link_dangling); unlink(full_sym_link_in_dir); rmdir(test_dir); printf("All files and directory cleaned up.\n");
printf("\n--- Summary ---\n"); printf("1. Hard links (link) point to the same inode as the original file.\n"); printf("2. Symbolic links (symlink) are separate files containing a path string.\n"); printf("3. Symbolic links can point to non-existent targets (dangling).\n"); printf("4. symlinkat allows creating symlinks relative to a directory file descriptor.\n");
return 0; }
|