[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#539338: mkfontscale: add option to recurse subdirectories



Hi,

thanks, Julien, for the comments, and sorry about the half-baked patch...

Julien Cristau wrote:
+	    && (stat(filename, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) {
this can lead to an infinite loop since you follow symlinks.  Juliusz
suggested limiting the recursion to something like 100.

Indeed. There would be an implicit upper bound of 2048 by the dsprintf implementation, but that's one more reason to check the return value and probably not good to rely on.

Please find attached a revised patch. The fixes to the manpage are mainly for reminding myself and I can split out the unrelated parts for cleaner commits.

Kind regards

T.
--
Thomas Viehmann, http://thomas.viehmann.net/
diff -Nru xfonts-utils-7.4+1/mkfontscale/mkfontscale.c xfonts-utils-7.4+1/mkfontscale/mkfontscale.c
--- xfonts-utils-7.4+1/mkfontscale/mkfontscale.c	2008-05-11 00:01:42.000000000 +0200
+++ xfonts-utils-7.4+1/mkfontscale/mkfontscale.c	2009-08-01 23:34:02.000000000 +0200
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <ctype.h>
+#include <sys/stat.h>
 
 #include <X11/Xos.h>
 #include <X11/fonts/fontenc.h>
@@ -63,6 +64,8 @@
 #define MAXFONTNAMELEN 1024
 #endif
 
+#define MAXDEPTHINRECURSIVESCAN 100
+
 char *encodings_array[] =
     { "ascii-0",
       "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
@@ -103,6 +106,7 @@
 static FT_Library ft_library;
 static float bigEncodingFuzz = 0.02;
 
+static int recurse;
 static int relative;
 static int doScalable;
 static int doBitmaps;
@@ -118,8 +122,8 @@
 {
     fprintf(stderr, 
             "mkfontscale [ -b ] [ -s ] [ -o filename ] [-x suffix ]\n"
-            "            [ -a encoding ] [ -f fuzz ] [ -l ] "
-            "            [ -e directory ] [ -p prefix ] [ -n ] [ -r ] \n"
+            "            [ -a encoding ] [ -f fuzz ] [ -l ]\n"
+            "            [ -e directory ] [ -p prefix ] [ -n ] [ -r ] [ -R ] \n"
             "            [-u] [-U] [ directory ]...\n");
 }
 
@@ -154,6 +158,7 @@
     doScalable = 1;
     onlyEncodings = 0;
     relative = 0;
+    recurse = 0;
     reencodeLegacy = 1;
     encodingsToDo = NULL;
 
@@ -217,6 +222,9 @@
         } else if(strcmp(argv[argn], "-r") == 0) {
             relative = 1;
             argn++;
+        } else if(strcmp(argv[argn], "-R") == 0) {
+            recurse = 1;
+            argn++;
         } else if(strcmp(argv[argn], "-l") == 0) {
             reencodeLegacy = !reencodeLegacy;
             argn++;
@@ -749,57 +757,20 @@
     return 0;
 }
 
+
 static int
-doDirectory(char *dirname_given, int numEncodings, ListPtr encodingsToDo)
+scanDirectory(char *dirname, char *dir_prefix, int xl, HashTablePtr entries, int depthtogo)
 {
-    char *dirname, *fontscale_name, *filename, *encdir;
-    FILE *fontscale, *encfile;
     DIR *dirp;
     struct dirent *entry;
+    struct stat statbuf;
+    ListPtr encoding, xlfd, lp;
+    char* filename;
+    char* prefixedname;
+    int rc, found;
+    int isBitmap=0;
     FT_Error ftrc;
     FT_Face face;
-    ListPtr encoding, xlfd, lp;
-    HashTablePtr entries;
-    HashBucketPtr *array;
-    int i, n, found, rc;
-    int isBitmap=0,xl=0;
-
-    if (exclusionSuffix)
-        xl = strlen (exclusionSuffix);
-
-    i = strlen(dirname_given);
-    if(i == 0)
-        dirname = dsprintf("./");
-    else if(dirname_given[i - 1] != '/')
-        dirname = dsprintf("%s/", dirname_given);
-    else
-        dirname = dsprintf("%s", dirname_given);
-
-    if(dirname == NULL) {
-        perror("dirname");
-        exit(1);
-    }
-
-    if (onlyEncodings) 
-	goto encodings;
-    
-    entries = makeHashTable();
-    if(doBitmaps && !doScalable) {
-        readFontScale(entries, dirname);
-    }
-
-    if(strcmp(outfilename, "-") == 0)
-        fontscale_name = NULL;
-    else {
-        if(outfilename[0] == '/')
-            fontscale_name = dsprintf("%s", outfilename);
-        else
-            fontscale_name = dsprintf("%s%s", dirname, outfilename);
-        if(fontscale_name == NULL) {
-            perror("fontscale_name");
-            exit(1);
-        }
-    }
 
     dirp = opendir(dirname);
     if(dirp == NULL) {
@@ -808,17 +779,6 @@
         return 0;
     }
 
-    if(fontscale_name == NULL)
-        fontscale = stdout;
-    else
-        fontscale = fopen(fontscale_name, "wb");
-
-    if(fontscale == NULL) {
-        fprintf(stderr, "%s: ", fontscale_name);
-        perror("fopen(w)");
-        return 0;
-    }
-
     while((entry = readdir(dirp)) != NULL) {
         int have_face = 0;
         char *xlfd_name = NULL;
@@ -831,7 +791,33 @@
 	}
 
         filename = dsprintf("%s%s", dirname, entry->d_name);
-
+        if (recurse && depthtogo>0 && strcmp(entry->d_name, ".") != 0
+	    && strcmp(entry->d_name, "..") != 0
+	    && stat(filename, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
+	    char* prefix;
+	    int retval;
+	    free(filename);
+	    filename = dsprintf("%s%s/", dirname, entry->d_name);
+	    prefix = dsprintf("%s%s/", dir_prefix, entry->d_name);
+	    if (filename == NULL || prefix == NULL) {
+	        perror("error allocating string (maximal length exeeded?)");
+	        return 0;
+	    }
+	    retval = scanDirectory(filename, prefix, xl, entries, depthtogo-1);
+	    free(filename);
+	    free(prefix);
+	    if (retval == 0) {
+	        closedir(dirp);
+	        return 0;
+	    }
+	    continue;
+	}       
+
+        prefixedname = dsprintf("%s%s", dir_prefix, entry->d_name);
+        if (prefixedname == NULL) {
+	    perror("error allocating string (maximal length exeeded?)");
+	    return 0;
+	}
         if(doBitmaps)
             rc = bitmapIdentify(filename, &xlfd_name);
         else
@@ -892,7 +878,7 @@
                 xlfd = listCons(s, xlfd);
             } else {
                 /* Not a reencodable font -- skip all the rest of the loop body */
-                putHash(entries, xlfd_name, entry->d_name, filePrio(entry->d_name));
+                putHash(entries, xlfd_name, prefixedname, filePrio(entry->d_name));
                 goto done;
             }
         }
@@ -926,7 +912,7 @@
                     found = 1;
                     snprintf(buf, MAXFONTNAMELEN, "%s-%s",
                             lp->value, encoding->value);
-                    putHash(entries, buf, entry->d_name, filePrio(entry->d_name));
+                    putHash(entries, buf, prefixedname, filePrio(entry->d_name));
                 }
             }
             for(encoding = extra_encodings; encoding; 
@@ -935,7 +921,7 @@
                     /* Do not set found! */
                     snprintf(buf, MAXFONTNAMELEN, "%s-%s",
                             lp->value, encoding->value);
-                    putHash(entries, buf, entry->d_name, filePrio(entry->d_name));
+                    putHash(entries, buf, prefixedname, filePrio(entry->d_name));
                 }
             }
         }
@@ -946,10 +932,76 @@
         }
         deepDestroyList(xlfd);
         xlfd = NULL;
+        free(prefixedname);
         free(filename);
     }
 
     closedir(dirp);
+    return 1;
+}
+
+
+static int
+doDirectory(char *dirname_given, int numEncodings, ListPtr encodingsToDo)
+{
+    char *dirname, *fontscale_name, *encdir;
+    FILE *fontscale, *encfile;
+    HashTablePtr entries;
+    HashBucketPtr *array;
+    ListPtr lp;
+    int i, n;
+    int xl=0;
+
+    if (exclusionSuffix)
+        xl = strlen (exclusionSuffix);
+
+    i = strlen(dirname_given);
+    if(i == 0)
+        dirname = dsprintf("./");
+    else if(dirname_given[i - 1] != '/')
+        dirname = dsprintf("%s/", dirname_given);
+    else
+        dirname = dsprintf("%s", dirname_given);
+
+    if(dirname == NULL) {
+        perror("dirname");
+        exit(1);
+    }
+
+    if (onlyEncodings) 
+	goto encodings;
+
+    entries = makeHashTable();
+    if(doBitmaps && !doScalable) {
+        readFontScale(entries, dirname);
+    }
+    if (scanDirectory(dirname, "", xl, entries, MAXDEPTHINRECURSIVESCAN) == 0)
+        return 0;
+
+    if(strcmp(outfilename, "-") == 0)
+        fontscale_name = NULL;
+    else {
+        if(outfilename[0] == '/')
+            fontscale_name = dsprintf("%s", outfilename);
+        else
+            fontscale_name = dsprintf("%s%s", dirname, outfilename);
+        if(fontscale_name == NULL) {
+            perror("fontscale_name");
+            exit(1);
+        }
+    }
+
+    if(fontscale_name == NULL)
+        fontscale = stdout;
+    else
+        fontscale = fopen(fontscale_name, "wb");
+
+    if(fontscale == NULL) {
+        fprintf(stderr, "%s: ", fontscale_name);
+        perror("fopen(w)");
+        return 0;
+    }
+
     n = hashElements(entries);
     fprintf(fontscale, "%d\n", n);
     array = hashArray(entries, 1);
diff -Nru xfonts-utils-7.4+1/mkfontscale/mkfontscale.man xfonts-utils-7.4+1/mkfontscale/mkfontscale.man
--- xfonts-utils-7.4+1/mkfontscale/mkfontscale.man	2008-04-28 21:23:47.000000000 +0200
+++ xfonts-utils-7.4+1/mkfontscale/mkfontscale.man	2009-08-01 23:41:55.000000000 +0200
@@ -31,10 +31,10 @@
 .I prefix
 ] [
 .B \-r
-.I prefix
+] [
+.B \-R
 ] [
 .B \-n
-.I prefix
 ] [
 .B \-\-
 ] [
@@ -107,7 +107,7 @@
 directory is scanned for encoding files, the list of which is then
 written to an "encodings.dir" file in every font directory.
 .TP
-.B -p
+.BI \-p " prefix"
 Specifies a prefix that is prepended to the encoding file path names
 when they are written to the "encodings.dir" file.  The prefix is
 prepended litterally: if a `/' is required between the prefix and the path
@@ -122,6 +122,10 @@
 .B \-e
 options.
 .TP
+.B \-R
+Recurse into subdirectories.  Scan subdirectories recursively and add
+fonts with relative paths.  Also recurse into symlinked directories.
+.TP
 .B \-n
 do not scan for fonts, do not write font directory files.  This option
 is useful when generating encoding directories only.

Reply to: