(file) Return to fixdist.c CVS log (file) (dir) Up to [OMI] / omi / scripts

  1 krisbash 1.1 /*
  2              **==============================================================================
  3              **
  4              ** Open Management Infrastructure (OMI)
  5              **
  6              ** Copyright (c) Microsoft Corporation
  7              ** 
  8              ** CtrlMd under the Apache CtrlM, Version 2.0 (the "CtrlM"); you may not 
  9              ** use this file except in compliance with the CtrlM. You may obtain a copy 
 10              ** of the CtrlM at 
 11              **
 12              **     http://www.apache.org/licenses/LICENSE-2.0 
 13              **
 14              ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15              ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
 16              ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
 17              ** MERCHANTABLITY OR NON-INFRINGEMENT. 
 18              **
 19              ** See the Apache 2 CtrlM for the specific language governing permissions 
 20              ** and limitations under the CtrlM.
 21              **
 22 krisbash 1.1 **==============================================================================
 23              */
 24              
 25              /*
 26              **==============================================================================
 27              **
 28              ** fixfiles:
 29              **
 30              **     This program performs three tasks:
 31              **
 32              **     (1) 'Fixes' text files (files made of ASCII 7-bit characters). This
 33              **         involves two changes:
 34              **
 35              **         (*) Converting "\r\n" sequences to "\n"
 36              **         (*) Appending "\n" to files that are missing this ending.
 37              **
 38              **     (2) Removes Windows internal files, such as:
 39              **
 40              **         sources
 41              **         sources.dep
 42              **         sources.inc
 43 krisbash 1.1 **         dirs
 44              **         buildchk.dbb
 45              **         buildchk.err
 46              **         buildchk.evt
 47              **         buildchk.log
 48              **         buildchk.prf
 49              **         buildchk.rec
 50              **         buildchk.trc
 51              **         buildchk.wrn
 52              **         buildfre.dbb
 53              **         buildfre.err
 54              **         buildfre.evt
 55              **         buildfre.log
 56              **         buildfre.prf
 57              **         buildfre.rec
 58              **         buildfre.trc
 59              **         buildfre.wrn
 60              **         makefile.cmn
 61              **         project.mk
 62              **         *.cmd
 63              **         *.rc
 64 krisbash 1.1 **
 65              **     (3) Makes script files executable (files beginning with "#!" sequences).
 66              **
 67              **     This fixdist script compiles this program and runs it on the fly.
 68              **
 69              **     Note that this program examines all files in the distribution and runs
 70              **     in under 2 seconds on Linux. It is slower on older Unix platforms but
 71              **     quite fast.
 72              **
 73              **==============================================================================
 74              */
 75              
 76              #include <sys/types.h>
 77              #include <dirent.h>
 78              #include <sys/types.h>
 79              #include <sys/stat.h>
 80              #include <unistd.h>
 81              #include <stdlib.h>
 82              #include <stdio.h>
 83              #include <string.h>
 84              #include <errno.h>
 85 krisbash 1.1 #include <ctype.h>
 86              #include <limits.h>
 87              
 88              #define FIXDIST_MAX_PATH 1024
 89              
 90              const char* arg0;
 91              
 92              typedef enum _Boolean
 93              {
 94                  BOOLEAN_FALSE = 0,
 95                  BOOLEAN_TRUE = 1,
 96              }
 97              Boolean;
 98              
 99              static int LoadFile(
100                  const char* path, 
101                  size_t extraBytes,
102                  char** dataOut, 
103                  size_t* sizeOut,
104                  unsigned int* mode)
105              {
106 krisbash 1.1     char* data;
107                  size_t size;
108                  FILE* is;
109              
110                  /* Clear output parameters */
111                  *dataOut = NULL;
112                  *sizeOut = 0;
113              
114                  /* Stat this file (to get the size) */
115                  {
116                      struct stat st;
117              
118                      if (stat(path, &st) != 0)
119                          return -1;
120              
121                      size = (size_t)st.st_size;
122                      *mode = (unsigned int)st.st_mode;
123                  }
124              
125                  /* Allocate the buffer */
126                  if (!(data = (char*)malloc(size + extraBytes)))
127 krisbash 1.1         return -1;
128              
129                  /* Open the file */
130                  if (!(is = fopen(path, "rb")))
131                  {
132                      free(data);
133                      return -1;
134                  }
135              
136                  /* Read the file into the buffer */
137                  {
138                      size_t n;
139                      char buf[BUFSIZ];
140                      char* end = data;
141              
142                      while ((n = fread(buf, 1, sizeof(buf), is)) > 0)
143                      {
144                          size_t remaining = size - (end - data);
145              
146                          /* No room in output buffer? (file grew since stat() called) */
147                          if (n > remaining)
148 krisbash 1.1             {
149                              fclose(is);
150                              free(data);
151                              return -1;
152                          }
153              
154                          memcpy(end, buf, n);
155                          end += n;
156                      }
157              
158                      if (ferror(is) != 0)
159                      {
160                          fclose(is);
161                          free(data);
162                          return -1;
163                      }
164                  }
165              
166                  /* Close the file */
167                  fclose(is);
168              
169 krisbash 1.1     /* Set output parameters */
170                  *dataOut = data;
171                  *sizeOut = size;
172              
173                  return 0;
174              }
175              
176              static int WriteFile(
177                  const char* path,
178                  const char* data, 
179                  size_t size)
180              {
181                  FILE* os;
182              
183                  /* Open file */
184                  if (!(os = fopen(path, "wb")))
185                      return -1;
186              
187                  /* Write file */
188                  {
189                      size_t n;
190 krisbash 1.1 
191                      while ((n = fwrite(data, 1, size, os)) > 0)
192                      {
193                          data += n;
194                          size -= n;
195                      }
196              
197                      if (ferror(os) != 0)
198                      {
199                          fclose(os);
200                          return -1;
201                      }
202                  }
203              
204                  fclose(os);
205              
206                  return size == 0 ? 0 : -1;
207              }
208              
209              static Boolean HasTextExtension(const char* path)
210              {
211 krisbash 1.1     static const char* extensions[] =
212                  {
213                      ".c",
214                      ".h",
215                      ".cpp",
216                      ".inc",
217                      ".mof",
218                  };
219                  size_t numExtensions = sizeof(extensions) / sizeof(extensions[0]);
220                  size_t i = 0;
221                  const char* p;
222                  
223                  if (!(p = strrchr(path, '.')))
224                  {
225                      return BOOLEAN_FALSE;
226                  }
227              
228                  for (i = 0; i < numExtensions; i++)
229                  {
230                      if (strcmp(p, extensions[i]) == 0)
231                          return BOOLEAN_TRUE;
232 krisbash 1.1     }
233              
234                  return BOOLEAN_FALSE;
235              }
236              
237              static Boolean IsText(
238                  const char* data, 
239                  size_t size, 
240                  size_t* line,
241                  char* ch)
242              {
243                  const char* p = data;
244                  const char* end = data + size;
245              
246                  *line = 1;
247                  *ch = '\0';
248              
249                  while (p != end)
250                  {
251                      char c = *p++;
252              
253 krisbash 1.1         if (c == '\n')
254                          (*line)++;
255              
256                      if (!isprint(c) && c != '\n' && c != '\r' && c != '\f' && c != '\t')
257                      {
258                          *ch = c;
259                          return BOOLEAN_FALSE;
260                      }
261                  }
262              
263                  return BOOLEAN_TRUE;
264              }
265              
266              static int FixFile(const char* path)
267              {
268                  char* data;
269                  size_t size;
270                  int modified = 0;
271                  const size_t extraBytes = 2;
272                  unsigned int mode;
273                  size_t line;
274 krisbash 1.1     char ch;
275              
276                  /* Load the file (allocate extra bytes for '\0' terminator and '\n' */
277                  if (LoadFile(path, extraBytes, &data, &size, &mode) != 0)
278                  {
279                      fprintf(stderr, "%s: failed to read file: %s\n", arg0, path);
280                      exit(1);
281                  }
282              
283                  /* Skip non-ASCII files */
284                  if (!IsText(data, size, &line, &ch))
285                  {
286                      if (HasTextExtension(path))
287                      {
288                          fprintf(
289                              stderr, 
290                              "%s(%u): warning: non-standard character: %u\n",
291                              path,
292                              (unsigned int)line,
293                              (unsigned char)ch);
294                      }
295 krisbash 1.1         return 0;
296                  }
297              
298                  /* Null terminate the buffer */
299                  data[size] = '\0';
300              
301                  /* Replace "\r\n" sequences with "\n" */
302                  {
303                      const char* p = data;
304                      char* q = data;
305                      const char* end = data + size;
306              
307                      while (p != end)
308                      {
309                          if (p[0] == '\r' && p[1] == '\n')
310                          {
311                              p++;
312                              size--;
313                              modified = 1;
314                          }
315              
316 krisbash 1.1             *q++ = *p++;
317                      }
318                  }
319              
320                  /* Add '\n' to the end if missing */
321                  if (size > 0 && data[size-1] != '\n')
322                  {
323                      data[size++] = '\n';
324                      data[size] = '\0';
325                      modified = 1;
326                  }
327              
328                  /* If file was modified above */
329                  if (modified)
330                  {
331                      /* Remove the original file */
332                      if (unlink(path) != 0)
333                      {
334                          fprintf(stderr, "%s: failed to remove file: %s\n", arg0, path);
335                          exit(1);
336                      }
337 krisbash 1.1 
338                      /* Write the new file */
339                      if (WriteFile(path, data, size) != 0)
340                      {
341                          fprintf(stderr, "%s: failed to write file: %s\n", arg0, path);
342                          exit(1);
343                      }
344              
345              #if 0
346                      printf("Modified %s\n", path);
347              #endif
348                  }
349              
350                  /* Make script file executable */
351              
352                  if (data[0] == '#' && data[1] == '!')
353                  {
354                      chmod(path, mode | S_IXUSR);
355                  }
356              
357                  free(data);
358 krisbash 1.1     return 0;
359              }
360              
361              static Boolean IsWindowsFile(const char* path)
362              {
363                  const char* names[] =
364                  {
365                      "sources",
366                      "sources.dep",
367                      "sources.inc",
368                      "dirs",
369                      "buildchk.dbb",
370                      "buildchk.err",
371                      "buildchk.evt",
372                      "buildchk.log",
373                      "buildchk.prf",
374                      "buildchk.rec",
375                      "buildchk.trc",
376                      "buildchk.wrn",
377                      "buildfre.dbb",
378                      "buildfre.err",
379 krisbash 1.1         "buildfre.evt",
380                      "buildfre.log",
381                      "buildfre.prf",
382                      "buildfre.rec",
383                      "buildfre.trc",
384                      "buildfre.wrn",
385                      "makefile.cmn",
386                      "project.mk"
387                  };
388                  const size_t numNames = sizeof(names) / sizeof(names[0]);
389                  size_t i;
390              
391                  for (i = 0; i < numNames; i++)
392                  {
393                      const char* p = strrchr(path, '/');
394              
395                      if (p)
396                          p++;
397                      else
398                          p = path;
399              
400 krisbash 1.1         if (strcmp(p, names[i]) == 0)
401                      {
402                          return BOOLEAN_TRUE;
403                      }
404              
405                      /* Check for files with the '.cmd' extension */
406                      if ((p = strrchr(path, '.')) && strcmp(p, ".cmd") == 0)
407                      {
408                          return BOOLEAN_TRUE;
409                      }
410              
411                      /* Check for files with the '.rc' extension */
412                      if ((p = strrchr(path, '.')) && strcmp(p, ".rc") == 0)
413                      {
414                          return BOOLEAN_TRUE;
415                      }
416                  }
417              
418                  /* Not a windows file */
419                  return BOOLEAN_FALSE;
420              }
421 krisbash 1.1 
422              static void FixDir(const char* path)
423              {
424                  DIR* dir;
425                  struct dirent* ent;
426                  char** dirs;
427                  size_t dirsSize = 0;
428                  size_t dirsCap = 64;
429                  size_t i;
430              
431                  /* Allocate dynamic array to hold directories */
432                  if (!(dirs = (char**)malloc(dirsCap * sizeof(char*))))
433                  {
434                      fprintf(stderr, "%s: malloc failed\n", arg0);
435                      exit(1);
436                  }
437              
438              #if 0
439                  printf("path{%s}\n", path);
440              #endif
441                  
442 krisbash 1.1     if (!(dir = opendir(path)))
443                  {
444                      fprintf(stderr, "%s: failed to open directory: %s\n", arg0, path);
445                      exit(1);
446                  }
447              
448                  while ((ent = readdir(dir)))
449                  {
450                      char buf[FIXDIST_MAX_PATH];
451                      struct stat st;
452              
453                      if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
454                          continue;
455              
456                      *buf = '\0';
457                      strncat(buf, path, sizeof(buf) - 1);
458                      strncat(buf, "/", sizeof(buf) - 1 - strlen(buf));
459                      strncat(buf, ent->d_name, sizeof(buf) - 1 - strlen(buf));
460              
461                      if (stat(buf, &st) != 0)
462                      {
463 krisbash 1.1             fprintf(stderr, "%s: failed to stat: %s\n", arg0, buf);
464                          exit(1);
465                      }
466              
467                      if (st.st_mode & S_IFDIR)
468                      {
469                          char* p = strdup(buf);
470              
471                          if (!p)
472                          {
473                              fprintf(stderr, "%s: out of memory\n", arg0);
474                              exit(1);
475                          }
476              
477                          if (dirsSize == dirsCap)
478                          {
479                              dirsCap *= 2;
480              
481                              if (!(dirs = (char**)realloc(dirs, dirsCap * sizeof(char*))))
482                              {
483                                  fprintf(stderr, "%s: realloc failed\n", arg0);
484 krisbash 1.1                     exit(1);
485                              }
486                          }
487              
488                          dirs[dirsSize++] = p;
489                      }
490                      else
491                      {
492                          if (IsWindowsFile(buf))
493                          {
494                              unlink(buf);
495              #if 0
496                              printf("Removed %s\n", buf);
497              #endif
498                          }
499                          else
500                          {
501                              FixFile(buf);
502                          }
503                      }
504                  }
505 krisbash 1.1 
506                  /* Close the directory */
507                  closedir(dir);
508              
509                  /* Process subdirectories */
510                  for (i = 0; i < dirsSize; i++)
511                  {
512                      FixDir(dirs[i]);
513                      free(dirs[i]);
514                  }
515              
516                  free(dirs);
517              }
518              
519              int main(int argc, char** argv)
520              {
521                  arg0 = argv[0];
522              
523                  if (argc != 1)
524                  {
525                      fprintf(stderr, "Usage: %s\n", arg0);
526 krisbash 1.1         exit(1);
527                  }
528              
529                  /* Fix all files in this directory and beneath it */
530                  FixDir(".");
531              
532                  return 0;
533              }

ViewCVS 0.9.2