1 /* 2 * List filesystem objects using the client library. 3 * 4 * Originally developed as fsaccess/op_list_objects.c, this should eventually 5 * use C library functions instead of client library functions. 6 * 7 * Copyright (C) 2019, 2022, 2024 Paul Boddie <paul@boddie.org.uk> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include <sys/stat.h> 30 #include <sys/types.h> 31 32 #include <e2access/format.h> /* get_permission_string */ 33 #include <e2access/path.h> 34 #include <systypes/format.h> 35 36 #define FMTnlinkd "%" pFMTnlink "d" 37 38 39 40 /* NOTE: For inclusion in the C library: stream acquisition and access. */ 41 42 #include <fsclient/client.h> 43 #include <systypes/env.h> 44 #include <systypes/fcntl.h> 45 46 file_t *output; 47 48 49 50 /* Show object details. */ 51 52 static void _show_object(const char *basename, struct stat *st) 53 { 54 char buffer[strlen(basename) + 64]; 55 56 sprintf(buffer, "%s%s %5d %5d %6ld " FMTnlinkd " %s\n", 57 S_ISDIR(st->st_mode) ? "d" : "-", 58 get_permission_string(st->st_mode), 59 st->st_uid, 60 st->st_gid, 61 st->st_size, 62 st->st_nlink, 63 basename); 64 65 client_write(output, buffer, strlen(buffer)); 66 } 67 68 /* Show an object in a directory. */ 69 70 static int _show_dirent(const char *dirname, struct dirent *dirent) 71 { 72 struct stat st; 73 char path[strlen(dirname) + 1 + strlen(dirent->d_name) + 1]; 74 75 sprintf(path, "%s/%s", dirname, dirent->d_name); 76 77 if (client_stat(path, &st)) 78 return 1; 79 80 _show_object(dirent->d_name, &st); 81 82 return 0; 83 } 84 85 /* List a directory or file. */ 86 87 static int _list_object(const char *path) 88 { 89 struct stat st; 90 file_t *reader; 91 struct dirent *dirent; 92 93 if (client_stat(path, &st)) 94 return 1; 95 96 if (S_ISDIR(st.st_mode)) 97 { 98 reader = client_opendir(path); 99 100 if (reader == NULL) 101 return 1; 102 103 /* Show the directory entries. */ 104 105 while ((dirent = client_readdir(reader)) != NULL) 106 { 107 if (_show_dirent(path, dirent)) 108 { 109 free(dirent); 110 return 1; 111 } 112 113 free(dirent); 114 } 115 116 client_close(reader); 117 } 118 else 119 _show_object(path_basename(path), &st); 120 121 return 0; 122 } 123 124 /* List an object in the filesystem. */ 125 126 static int list_object(const char *path) 127 { 128 /* Emit each object's name. */ 129 130 client_write(output, path, strlen(path)); 131 client_write(output, "\n", 1); 132 133 /* List individual files or directories. */ 134 135 if (_list_object(path)) 136 { 137 /* NOTE: Should write via a standard error stream provided in the same 138 way as the output stream. */ 139 140 fprintf(stderr, "Failed to list object: %s\n", path); 141 return 1; 142 } 143 144 return 0; 145 } 146 147 /* List objects in the filesystem. */ 148 149 int main(int argc, char *argv[]) 150 { 151 int i; 152 153 /* NOTE: For inclusion in the C library: stream acquisition and access. */ 154 155 output = client_get_stream(ENV_OUTPUT_STREAM_NAME, O_WRONLY); 156 157 /* List the top level without any argument. */ 158 159 if (argc < 2) 160 { 161 if (list_object("")) 162 return 1; 163 } 164 else 165 { 166 /* Otherwise, list all specified objects. */ 167 168 for (i = 1; i < argc; i++) 169 { 170 if (list_object(argv[i])) 171 return 1; 172 } 173 } 174 175 /* NOTE: For inclusion in the C library: stream acquisition and access. */ 176 177 client_flush(output); 178 179 return 0; 180 } 181 182 /* vim: tabstop=4 expandtab shiftwidth=4 183 */