chiark / gitweb /
@@ -1,3 +1,11 @@
authorianmdlvl <ianmdlvl>
Sat, 22 Jul 2006 14:56:42 +0000 (14:56 +0000)
committerianmdlvl <ianmdlvl>
Sat, 22 Jul 2006 14:56:42 +0000 (14:56 +0000)
+chiark-utils (4.1.1) unstable; urgency=low
+
+  * summer sorts the output and identifies hardlink
+    targets instead of printing link count.
+
+
+ --
+
 chiark-utils (4.1.0) unstable; urgency=low

   New facilities:

cprogs/summer.c
debian/changelog

index 773719f..887409d 100644 (file)
@@ -7,7 +7,8 @@
 
 #define _GNU_SOURCE
 
-#include <ftw.h>
+#include <search.h>
+#include <dirent.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #define CSUMXL 32
 
 static int quiet=0, hidectime=0, hideatime=0;
-static int hidedirsizelinkcount=0, hidelinkmtime=0;
+static int hidedirsize=0, hidelinkmtime=0;
 static int filenamefieldsep=' ';
 static FILE *errfile;
 
+static void malloc_fail(void) { perror("summer: alloc failed"); exit(12); }
+
+static void *mmalloc(size_t sz) {
+  void *r;
+  r= malloc(sz);  if (!r) malloc_fail();
+  return r;
+}
+
+static void *mrealloc(void *p, size_t sz) {
+  void *r;
+  r= realloc(p, sz);  if (!r && sz) malloc_fail();
+  return r;
+}
+
 static void fn_escaped(FILE *f, const char *fn) {
   int c;
   while ((c= *fn++)) {
@@ -121,38 +136,67 @@ static void csum_str(const char *s) {
   printf("%-*s", CSUMXL, s);
 }
 
-struct FTW;
+static void linktargpath(const char *linktarg) {
+  printf(" -> ");
+  fn_escaped(stdout, linktarg);
+}
+
+struct hardlink {
+  dev_t dev;
+  ino_t ino;
+  char path[1];
+};
+static void *hardlinks;
+
+static void pu10(void) { printf(" %10s", "?"); }
+
+static int hardlink_compar(const void *av, const void *bv) {
+  const struct hardlink *a=av, *b=bv;
+  if (a->ino != b->ino) return b->ino - a->ino;
+  return b->dev - a->dev;
+}
 
-static int item(const char *path, const struct stat *stab,
-               int flag, struct FTW *ftws) {
+static void recurse(const char *path);
+
+static void node(const char *path) {
   char linktarg[MAXFN+1];
+  struct hardlink *foundhl;
+  const struct stat *stab;
+  struct stat stabuf;
+  int r;
 
-  switch (flag) {
-  case FTW_D:
-  case FTW_F:
-  case FTW_SL:
-    if (S_ISREG(stab->st_mode)) csum_file(path);
-    else if (S_ISDIR(stab->st_mode)) csum_str("dir");
-    else if (S_ISCHR(stab->st_mode)) csum_dev('c',stab);
-    else if (S_ISBLK(stab->st_mode)) csum_dev('b',stab);
-    else if (S_ISFIFO(stab->st_mode)) csum_str("pipe");
-    else if (S_ISLNK(stab->st_mode)) csum_str("link");
-    else if (S_ISSOCK(stab->st_mode)) csum_str("sock");
-    else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
-    break;
-
-  case FTW_NS:
-  case FTW_DNR:
-    problem_e(path,CSUMXL,"inaccessible");
-    break;
-
-  default:
-    problem(path,CSUMXL,"ftw flag 0x%x: %s",flag);
+  r= lstat(path, &stabuf);
+  stab= r ? 0 : &stabuf;
+
+  foundhl= 0;
+  if (stab && stab->st_nlink>1) {
+    struct hardlink *newhl, **foundhl_node;
+    newhl= mmalloc(sizeof(*newhl) + strlen(path));
+    newhl->dev= stab->st_dev;
+    newhl->ino= stab->st_ino;
+    foundhl_node= tsearch(newhl, &hardlinks, hardlink_compar);
+    if (!foundhl_node) malloc_fail();
+    foundhl= *foundhl_node;
+    if (foundhl!=newhl) {
+      free(newhl); /* hardlink to an earlier object */
+    } else {
+      foundhl= 0; /* new object with link count>1 */
+      strcpy(newhl->path, path);
+    }
   }
 
-  if (S_ISLNK(stab->st_mode)) {
-    int r;
-
+  if (!stab) problem_e(path,CSUMXL,"inaccessible");
+  else if (foundhl) csum_str("hardlink");
+  else if (S_ISREG(stab->st_mode)) csum_file(path);
+  else if (S_ISDIR(stab->st_mode)) csum_str("dir");
+  else if (S_ISCHR(stab->st_mode)) csum_dev('c',stab);
+  else if (S_ISBLK(stab->st_mode)) csum_dev('b',stab);
+  else if (S_ISFIFO(stab->st_mode)) csum_str("pipe");
+  else if (S_ISLNK(stab->st_mode)) csum_str("symlink");
+  else if (S_ISSOCK(stab->st_mode)) csum_str("sock");
+  else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
+
+  if (stab && S_ISLNK(stab->st_mode)) {
     r= readlink(path, linktarg, sizeof(linktarg)-1);
     if (r==sizeof(linktarg)) { problem(path,-1,"readlink too big"); r=-1; }
     else if (r<0) { problem_e(path,-1,"readlink"); }
@@ -162,51 +206,118 @@ static int item(const char *path, const struct stat *stab,
     else linktarg[r]= 0;
   }
 
-  if (S_ISDIR(stab->st_mode) && hidedirsizelinkcount)
-    printf(" %10s %4s","dir","dir");
-  else
-    printf(" %10lu %4d", 
-          (unsigned long)stab->st_size,
-          (int)stab->st_nlink);
-
-  printf(" %4o %10ld %10ld",
-        (unsigned)stab->st_mode & 07777U,
-        (unsigned long)stab->st_uid,
-        (unsigned long)stab->st_gid);
+  if (stab) {
+    if (S_ISDIR(stab->st_mode) && hidedirsize)
+      printf(" %10s","dir");
+    else
+      printf(" %10lu", 
+            (unsigned long)stab->st_size);
+
+    printf(" %4o %10ld %10ld",
+          (unsigned)stab->st_mode & 07777U,
+          (unsigned long)stab->st_uid,
+          (unsigned long)stab->st_gid);
+  } else {
+    printf(" %10s %4s %10s %10s", "?","?","?","?");
+  }
 
-  if (!hideatime)
-    printf(" %10lu",
-          (unsigned long)stab->st_atime);
+  if (!hideatime) {
+    if (stab)
+      printf(" %10lu",
+            (unsigned long)stab->st_atime);
+    else
+      pu10();
+  }
 
-  if (S_ISLNK(stab->st_mode) && hidelinkmtime)
-    printf(" %10s","link");
+  if (stab)
+    if (S_ISLNK(stab->st_mode) && hidelinkmtime)
+      printf(" %10s","link");
+    else
+      printf(" %10lu",
+            (unsigned long)stab->st_mtime);
   else
-    printf(" %10lu",
-          (unsigned long)stab->st_mtime);
+    pu10();
+
+  if (!hidectime) {
+    if (stab)
+      printf(" %10lu",
+            (unsigned long)stab->st_ctime);
+    else
+      pu10();
+  }
 
-  if (!hidectime)
-    printf(" %10lu",
-          (unsigned long)stab->st_ctime);
   putchar(filenamefieldsep);
   fn_escaped(stdout, path);
 
-  if (S_ISLNK(stab->st_mode)) {
-    printf(" -> ");
-    fn_escaped(stdout, linktarg);
-  }
+  if (foundhl) linktargpath(foundhl->path);
+  if (stab && S_ISLNK(stab->st_mode)) linktargpath(linktarg);
+
   putchar('\n');
 
   if (ferror(stdout)) { perror("summer: stdout"); exit(12); }
-  return 0;
+
+  if (stab && S_ISDIR(stab->st_mode))
+    recurse(path);
 }
 
 static void process(const char *startpoint) {
-  int r;
   if (!quiet)
     fprintf(stderr,"summer: processing: %s\n",startpoint);
-  r= nftw(startpoint, item, MAXDEPTH, FTW_MOUNT|FTW_PHYS);
-  if (r) { fprintf(stderr, "summer: nftw failed: %s: %s\n",
-                  strerror(errno), startpoint); exit(4); }
+  node(startpoint);
+  tdestroy(hardlinks,free);
+  hardlinks= 0;
+}
+
+static int recurse_maxlen;
+
+static int recurse_filter(const struct dirent *de) {
+  int l;
+  if (de->d_name[0]=='.' &&
+      (de->d_name[1]==0 ||
+       (de->d_name[1]=='.' &&
+       de->d_name[2]==0)))
+    return 0;
+  l= strlen(de->d_name);
+  if (l > recurse_maxlen) recurse_maxlen= l;
+  return 1;
+}
+
+static int recurse_compar(const void *av, const void *bv) {
+  const struct dirent *const *a=av, *const *b=bv;
+  return strcmp((*a)->d_name, (*b)->d_name);
+}
+
+static void recurse(const char *path) {
+  static char *buf;
+  static int buf_allocd;
+  
+  struct dirent **namelist, *const *de;
+  char *subpathp;
+  int nentries, pathl, esave, buf_want, i;
+
+  pathl= strlen(path);
+  recurse_maxlen= 2;
+  nentries= scandir(path, &namelist, recurse_filter, recurse_compar);
+  esave= errno;
+  buf_want= pathl+1+recurse_maxlen+1;
+  if (buf_want > buf_allocd) {
+    buf= mrealloc(buf, buf_want);
+    buf_allocd= buf_want;
+  }
+  strcpy(buf,path);
+  buf[pathl]= '/';
+  subpathp= buf+pathl+1;
+  if (nentries < 0) {
+    strcpy(subpathp,"\\?");  errno= esave;
+    problem_e(buf,-1,"scandir failed");
+    return;
+  }
+  for (i=0, de=namelist; i<nentries; i++, de++) {
+    strcpy(subpathp, (*de)->d_name);
+    node(buf);
+    free(*de);
+  }
+  free(namelist);
 }
 
 static void from_stdin(void) {
@@ -249,7 +360,7 @@ int main(int argc, const char *const *argv) {
        filenamefieldsep= '\t';
        break;
       case 'D':
-       hidedirsizelinkcount= 1;
+       hidedirsize= 1;
        break;
       case 'b':
        hidelinkmtime= 1;
index 8142387..82615ce 100644 (file)
@@ -1,3 +1,11 @@
+chiark-utils (4.1.1) unstable; urgency=low
+
+  * summer sorts the output and identifies hardlink
+    targets instead of printing link count.
+  
+
+ --
+
 chiark-utils (4.1.0) unstable; urgency=low
 
   New facilities: