[PATCH + RFC] libXfont catalogue:<dir> rescan on dir changes

Ademar de Souza Reis Jr. ademar at mandriva.com.br
Tue Jul 10 15:11:56 PDT 2007


Hi there.

The current catalogue:<dir> implementation on libXfont rescan the
font paths only if <dir> (fontpath.d) has its mtime changed.

The problem is that most of the time, what changes is not the
fontpath.d dir, but the dirs pointed by the symlinks (e.g. some
fonts are installed inside the same directory, package managers
write the symlink before the directory is changed, user can run
mkfontdir, etc).

I'm not familiar enough with libXfont to implement an optimal
solution, so I cooked a simple and non-intrusive patch that does
the work by forcing a rescan in case any of the dirs have its
mtime changed (below, applies on top of my previous libXfont
patches).

My solution is not optimal since it runs through the fontpath.d
dir twice (once to check mtime and once to build the FPEs), but
it works and accoding to my tests the performance cost is far
from being noticeable.

So, what do you think? Any chances of merging such a patch?

Thanks and best regards,
  - Ademar

 src/fontfile/catalogue.c |   69 +++++++++++++++++++++++++++++++++++----------
 1 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/src/fontfile/catalogue.c b/src/fontfile/catalogue.c
index ee68163..84e893c 100644
--- a/src/fontfile/catalogue.c
+++ b/src/fontfile/catalogue.c
@@ -124,6 +124,21 @@ CatalogueUnrefFPEs (FontPathElementPtr fpe)
 }
 
 static int
+NormalizeRelativePath(char *path, const char *root, int pathsize)
+{
+    int rootlen;
+    if (path[0] != '/')
+    {
+        rootlen = strlen(root);
+        memmove(path + rootlen + 1, path, pathsize - rootlen - 1);
+        memcpy(path, root, rootlen);
+        memcpy(path + rootlen, "/", 1);
+        return rootlen + 1;
+    }
+    return 0;
+}
+
+static int
 CatalogueRescan (FontPathElementPtr fpe)
 {
     CataloguePtr	cat = fpe->private;
@@ -136,14 +151,9 @@ CatalogueRescan (FontPathElementPtr fpe)
     DIR			*dir;
     struct dirent	*entry;
     int			len;
-    int			pathlen;
+    time_t		mtime = cat->mtime;
 
     path = fpe->name + strlen(CataloguePrefix);
-    if (stat(path, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
-	return BadFontPath;
-
-    if (statbuf.st_mtime <= cat->mtime)
-	return Successful;
 
     dir = opendir(path);
     if (dir == NULL)
@@ -152,6 +162,42 @@ CatalogueRescan (FontPathElementPtr fpe)
 	return BadFontPath;
     }
 
+    while (entry = readdir(dir), entry != NULL)
+    {
+	snprintf(link, sizeof link, "%s/%s", path, entry->d_name);
+	len = readlink(link, dest, sizeof dest);
+	if (len < 0)
+	    continue;
+
+	dest[len] = '\0';
+
+	len += NormalizeRelativePath(dest, path, sizeof dest);
+
+	if (stat(dest, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
+	    continue;
+
+	if (statbuf.st_mtime < cat->mtime)
+	    continue;
+
+	if (statbuf.st_mtime > mtime)
+	    mtime = statbuf.st_mtime;
+    }
+
+    if (stat(path, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
+    {
+	closedir(dir);
+	return BadFontPath;
+    }
+
+    if (cat->mtime >= mtime && cat->mtime >= statbuf.st_mtime)
+    {
+	closedir(dir);
+	return Successful;
+    }
+    else
+	cat->mtime = mtime > statbuf.st_mtime ? mtime : statbuf.st_mtime;
+
+    rewinddir(dir);
     CatalogueUnrefFPEs (fpe);
     while (entry = readdir(dir), entry != NULL)
     {
@@ -162,14 +208,7 @@ CatalogueRescan (FontPathElementPtr fpe)
 
 	dest[len] = '\0';
 
-	if (dest[0] != '/')
-	{
-	    pathlen = strlen(path);
-	    memmove(dest + pathlen + 1, dest, sizeof dest - pathlen - 1);
-	    memcpy(dest, path, pathlen);
-	    memcpy(dest + pathlen, "/", 1);
-	    len += pathlen + 1;
-	}
+	len += NormalizeRelativePath(dest, path, sizeof dest);
 
 	attrib = strchr(link, ':');
 	if (attrib && len + strlen(attrib) < sizeof dest)
@@ -223,8 +262,6 @@ CatalogueRescan (FontPathElementPtr fpe)
     qsort(cat->fpeList,
 	  cat->fpeCount, sizeof cat->fpeList[0], ComparePriority);
 
-    cat->mtime = statbuf.st_mtime;
-
     return Successful;
 }
 
-- 
1.5.2.2



More information about the xorg mailing list