/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include /* * Compare a string to a mask * Mask characters: * @ - uppercase letter * # - lowercase letter * & - hex digit * # - digit * * - swallow remaining characters * - exact match for any other character */ static int checkmask(const char *data, const char *mask) { int i, ch, d; for (i = 0; mask[i] != '\0' && mask[i] != '*'; i++) { ch = mask[i]; d = data[i]; if (ch == '@') { if (!isupper(d)) return 0; } else if (ch == '$') { if (!islower(d)) return 0; } else if (ch == '#') { if (!isdigit(d)) return 0; } else if (ch == '&') { if (!isxdigit(d)) return 0; } else if (ch != d) return 0; } if (mask[i] == '*') return 1; else return (data[i] == '\0'); } /* * Converts 8 hex digits to a time integer */ static int hex2sec(const char *x) { int i, ch; unsigned int j; for (i = 0, j = 0; i < 8; i++) { ch = x[i]; j <<= 4; if (isdigit(ch)) j |= ch - '0'; else if (isupper(ch)) j |= ch - ('A' - 10); else j |= ch - ('a' - 10); } if (j == 0xffffffff) return -1; /* so that it works with 8-byte ints */ else return j; } int main(int argc, char **argv) { int i, ver; DIR *d; struct dirent *e; const char *s; FILE *fp; char path[FILENAME_MAX + 1]; char line[1035]; time_t date, lmod, expire; unsigned int len; struct tm ts; char sdate[30], slmod[30], sexpire[30]; const char time_format[] = "%e %b %Y %R"; if (argc != 2) { printf("Usage: cls directory\n"); exit(0); } d = opendir(argv[1]); if (d == NULL) { perror("opendir"); exit(1); } for (;;) { e = readdir(d); if (e == NULL) break; s = e->d_name; if (s[0] == '.' || s[0] == '#') continue; sprintf(path, "%s/%s", argv[1], s); fp = fopen(path, "r"); if (fp == NULL) { perror("fopen"); continue; } if (fgets(line, 1034, fp) == NULL) { perror("fgets"); fclose(fp); continue; } if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n")) { fprintf(stderr, "Bad cache file\n"); fclose(fp); continue; } date = hex2sec(line); lmod = hex2sec(line + 9); expire = hex2sec(line + 18); ver = hex2sec(line + 27); len = hex2sec(line + 35); if (fgets(line, 1034, fp) == NULL) { perror("fgets"); fclose(fp); continue; } fclose(fp); i = strlen(line); if (strncmp(line, "X-URL: ", 7) != 0 || line[i - 1] != '\n') { fprintf(stderr, "Bad cache file\n"); continue; } line[i - 1] = '\0'; if (date != -1) { ts = *gmtime(&date); strftime(sdate, 30, time_format, &ts); } else strcpy(sdate, "-"); if (lmod != -1) { ts = *gmtime(&lmod); strftime(slmod, 30, time_format, &ts); } else strcpy(slmod, "-"); if (expire != -1) { ts = *gmtime(&expire); strftime(sexpire, 30, time_format, &ts); } else strcpy(sexpire, "-"); printf("%s: %d; %s %s %s\n", line + 7, ver, sdate, slmod, sexpire); } closedir(d); return 0; }