1.1 --- a/libe2access/host/e2access.c Sat Feb 19 00:43:46 2022 +0100
1.2 +++ b/libe2access/host/e2access.c Sat Feb 19 00:44:46 2022 +0100
1.3 @@ -41,6 +41,10 @@
1.4
1.5 const int BUFSIZE = 4096;
1.6
1.7 +/* Maximum number of arguments in scripts. */
1.8 +
1.9 +const int MAX_ARGS = 32;
1.10 +
1.11
1.12
1.13 /* Alternative metadata set by options. */
1.14 @@ -447,7 +451,7 @@
1.15
1.16 if (utils_list_dir(fs, path))
1.17 {
1.18 - fprintf(stderr, "Failed to list directory: %s\n", path);
1.19 + fprintf(stderr, "Failed to list object: %s\n", path);
1.20 return 1;
1.21 }
1.22 }
1.23 @@ -576,6 +580,169 @@
1.24 return _remove(fs, argc, argv, 0);
1.25 }
1.26
1.27 +/* Read a line from a file into the given buffer. */
1.28 +
1.29 +struct read_line_state
1.30 +{
1.31 + char *buffer, *start, *end, *eolp;
1.32 + size_t remaining;
1.33 +};
1.34 +
1.35 +static char *read_line(FILE *fp, struct read_line_state *state)
1.36 +{
1.37 + size_t nread;
1.38 +
1.39 + do
1.40 + {
1.41 + do
1.42 + {
1.43 + /* Search for a newline character in any available text. */
1.44 +
1.45 + if (state->end > state->start)
1.46 + {
1.47 + state->eolp = strchr(state->start, '\n');
1.48 +
1.49 + if (state->eolp != NULL)
1.50 + {
1.51 + *(state->eolp) = '\0';
1.52 + return state->eolp;
1.53 + }
1.54 + }
1.55 +
1.56 + /* Obtain more text if necessary. */
1.57 +
1.58 + nread = fread(state->end, sizeof(char), state->remaining, fp);
1.59 +
1.60 + /* Handle end of file condition. */
1.61 +
1.62 + if (!nread)
1.63 + {
1.64 + if (state->end > state->start)
1.65 + return state->end;
1.66 + else
1.67 + return NULL;
1.68 + }
1.69 +
1.70 + /* Zero-terminate the string for searching. */
1.71 +
1.72 + *(state->end + nread) = '\0';
1.73 +
1.74 + /* Advance the end of string and subtract remaining space. */
1.75 +
1.76 + state->end += nread;
1.77 + state->remaining -= nread;
1.78 + }
1.79 + while (state->remaining);
1.80 +
1.81 + /* Copy the remaining text to the start of the buffer. */
1.82 +
1.83 + if (state->start > state->buffer)
1.84 + {
1.85 + strcpy(state->buffer, state->start);
1.86 +
1.87 + state->end -= (state->start - state->buffer);
1.88 + state->start = state->buffer;
1.89 + state->remaining = BUFSIZE - 1 - (state->end - state->buffer);
1.90 + }
1.91 + }
1.92 + while (state->remaining);
1.93 +
1.94 + return NULL;
1.95 +}
1.96 +
1.97 +/* Parse the text in the given region, returning details of arguments. */
1.98 +
1.99 +static void parse_line(char *start, char *end, int *num_args, char *args[], const int max_args)
1.100 +{
1.101 + *num_args = 0;
1.102 +
1.103 + while ((start != NULL) && (start < end) && (*num_args < max_args))
1.104 + {
1.105 + args[*num_args] = start;
1.106 + (*num_args)++;
1.107 +
1.108 + /* NOTE: Only handling spaces as delimiters. */
1.109 +
1.110 + start = strchr(start, ' ');
1.111 +
1.112 + if (start != NULL)
1.113 + {
1.114 + *start = '\0';
1.115 +
1.116 + if (start < end)
1.117 + start++;
1.118 + }
1.119 + }
1.120 +}
1.121 +
1.122 +/* Read operations from a script file. */
1.123 +
1.124 +enum op_results
1.125 +{
1.126 + OP_SUCCESS = 0,
1.127 + OP_FAILED = 1,
1.128 + OP_UNKNOWN = 2,
1.129 +};
1.130 +
1.131 +int handle_op_result(const char *operation, enum op_results op_result)
1.132 +{
1.133 + if (op_result == OP_UNKNOWN)
1.134 + {
1.135 + fprintf(stderr, "Operation not recognised: %s\n", operation);
1.136 + return 1;
1.137 + }
1.138 + else if (op_result == OP_FAILED)
1.139 + {
1.140 + fprintf(stderr, "Operation failed: %s\n", operation);
1.141 + return 1;
1.142 + }
1.143 + else
1.144 + return 0;
1.145 +}
1.146 +
1.147 +enum op_results run_operation(ext2_filsys fs, const char *operation, int argc, char *argv[]);
1.148 +
1.149 +int run_script(ext2_filsys fs, int argc, char *argv[])
1.150 +{
1.151 + FILE *fp;
1.152 + char buffer[BUFSIZE];
1.153 + struct read_line_state state;
1.154 + enum op_results op_result;
1.155 + int num_args;
1.156 + char *args[MAX_ARGS];
1.157 + int i;
1.158 +
1.159 + for (i = 0; i < argc; i++)
1.160 + {
1.161 + fp = fopen(argv[i], "r");
1.162 +
1.163 + state.buffer = buffer;
1.164 + state.start = buffer;
1.165 + state.end = buffer;
1.166 + state.remaining = BUFSIZE - 1;
1.167 +
1.168 + while (read_line(fp, &state) != NULL)
1.169 + {
1.170 + parse_line(state.start, state.eolp, &num_args, args, MAX_ARGS);
1.171 +
1.172 + if (num_args > 1)
1.173 + {
1.174 + op_result = run_operation(fs, args[0], num_args - 1, &args[1]);
1.175 +
1.176 + if (handle_op_result(args[0], op_result))
1.177 + return 1;
1.178 + }
1.179 +
1.180 + state.start = state.eolp + 1;
1.181 + }
1.182 +
1.183 + fclose(fp);
1.184 + }
1.185 +
1.186 + return 0;
1.187 +}
1.188 +
1.189 +
1.190
1.191
1.192 /* Help message. */
1.193 @@ -592,14 +759,21 @@
1.194 \n\
1.195 -m MASK Set mode/permissions mask for new directories\n\
1.196 \n\
1.197 -Operations:\n\
1.198 +Transfer operations:\n\
1.199 \n\
1.200 copy-in Copy files into a directory within the image\n\
1.201 copy-out Copy files from the image into a directory\n\
1.202 +\n\
1.203 +Image operations:\n\
1.204 +\n\
1.205 ls List files and directories within the image\n\
1.206 mkdir Make directories within the image\n\
1.207 rm Remove non-directory objects from the image\n\
1.208 rmdir Remove directories from the image\n\
1.209 +\n\
1.210 +Script operations:\n\
1.211 +\n\
1.212 + script Read operations from a script file\n\
1.213 ";
1.214
1.215 /* Operations exposed by the program. */
1.216 @@ -617,9 +791,34 @@
1.217 {"mkdir", make_dirs},
1.218 {"rm", remove_non_dirs},
1.219 {"rmdir", remove_dirs},
1.220 + {"script", run_script},
1.221 {NULL, NULL},
1.222 };
1.223
1.224 +/* Invocation of operations. */
1.225 +
1.226 +enum op_results run_operation(ext2_filsys fs, const char *operation, int argc, char *argv[])
1.227 +{
1.228 + struct operation *op;
1.229 + int exitcode;
1.230 +
1.231 + for (op = &operations[0]; op->name != NULL; op++)
1.232 + {
1.233 + if (!strcmp(operation, op->name))
1.234 + {
1.235 + exitcode = op->fn(fs, argc, argv);
1.236 + if (exitcode)
1.237 + return OP_FAILED;
1.238 + break;
1.239 + }
1.240 + }
1.241 +
1.242 + if (op->name == NULL)
1.243 + return OP_UNKNOWN;
1.244 +
1.245 + return OP_SUCCESS;
1.246 +}
1.247 +
1.248 /* Main program. */
1.249
1.250 int main(int argc, char *argv[])
1.251 @@ -632,9 +831,9 @@
1.252 /* Program argument details. */
1.253
1.254 char **args;
1.255 - char *fsname, *operation, *filename;
1.256 + char *fsname, *filename;
1.257 int num_args;
1.258 - struct operation *op;
1.259 + enum op_results op_result;
1.260
1.261 /* Parse program options and initialise the argument details. */
1.262
1.263 @@ -672,26 +871,8 @@
1.264
1.265 /* Perform the requested operation. */
1.266
1.267 - operation = args[1];
1.268 - args = &args[2];
1.269 - num_args -= 2;
1.270 -
1.271 - for (op = &operations[0]; op->name != NULL; op++)
1.272 - {
1.273 - if (!strcmp(operation, op->name))
1.274 - {
1.275 - exitcode = op->fn(fs, num_args, args);
1.276 - if (exitcode)
1.277 - fprintf(stderr, "Operation failed: %s\n", operation);
1.278 - break;
1.279 - }
1.280 - }
1.281 -
1.282 - if (op->name == NULL)
1.283 - {
1.284 - fprintf(stderr, "Operation not recognised: %s\n", operation);
1.285 - exitcode = 1;
1.286 - }
1.287 + op_result = run_operation(fs, args[1], num_args - 2, &args[2]);
1.288 + exitcode = handle_op_result(args[1], op_result);
1.289
1.290 /* Close the filesystem image. */
1.291