Commit c7eedc4e authored by Raymond Toy's avatar Raymond Toy
Browse files

Fix #130: Implement file_author in C

parent 84aced83
Loading
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -1079,13 +1079,21 @@ optionally keeping some of the most recent old versions."
		 :pathname file
		 :format-control (intl:gettext "~S doesn't exist.")
		 :format-arguments (list file)))
	(multiple-value-bind (winp dev ino mode nlink uid)
			     (unix:unix-stat name)
	  (declare (ignore dev ino mode nlink))
	  (when winp
            (let ((user-info (unix:unix-getpwuid uid)))
              (when user-info
                (unix:user-info-name user-info))))))))
	;; unix-namestring converts "." to "".  Convert it back to
	;; "." so we can stat the current directory.  (Perhaps
	;; that's a bug in unix-namestring?)
	(when (zerop (length name))
	  (setf name "."))
	(let (author)
	  (unwind-protect
	       (progn
		 (setf author (alien:alien-funcall
			       (alien:extern-alien "os_file_author"
						   (function (alien:* c-call:c-string) c-call:c-string))
			       (unix::%name->file name)))
		 (unless (alien:null-alien author)
		   (alien:cast author c-call:c-string)))
	    (alien:free-alien author))))))


;;;; DIRECTORY.
+57 −1
Original line number Diff line number Diff line
@@ -5,13 +5,17 @@

*/

#include <assert.h>
#include <errno.h>
#include <math.h>
#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <time.h>

#include "os.h"
@@ -717,6 +721,59 @@ os_lstat(const char* path, u_int64_t *dev, u_int64_t *ino, unsigned int *mode, u
    return rc;
}

/*
 * Interface for file-author.  Given a pathname, returns a new string
 * holding the author of the file or NULL if some error occurred.  The
 * caller is responsible for freeing the memory used by the string.
 */
char *
os_file_author(const char *path)
{
    struct stat sb;
    char initial[1024];
    char *buffer, *obuffer;
    size_t size;
    struct passwd pwd;
    struct passwd *ppwd;
    char *result;

    if (stat(path, &sb) != 0) {
        return NULL;
    }

    result = NULL;
    buffer = initial;
    obuffer = NULL;
    size = sizeof(initial) / sizeof(initial[0]);

    /*
     * Keep trying with larger buffers until a maximum is reached.  We
     * assume (1 << 20) is large enough for any OS.
     */
    while (size <= (1 << 20)) {
        switch (getpwuid_r(sb.st_uid, &pwd, buffer, size, &ppwd)) {
          case 0:
              /* Success, though we might not have a matching entry */
              result = (ppwd == NULL) ? NULL : strdup(pwd.pw_name);
              goto exit;
          case ERANGE:
              /* Buffer is too small, double its size and try again */
              size *= 2;
              obuffer = (buffer == initial) ? NULL : buffer;
              if ((buffer = realloc(obuffer, size)) == NULL) {
                  goto exit;
              }
              continue;
          default:
              /* All other errors */
              goto exit;
        }
    }
exit:
    free(obuffer);
    
    return result;
}
/*
 * For Linux and solaris, software-version returns the concatenation
 * of the uname release and version fields.  For BSD (including
@@ -769,4 +826,3 @@ os_software_type()

    return os_name;
}
    
+7 −0
Original line number Diff line number Diff line
@@ -670,3 +670,10 @@
		 (err (relerr value answer)))
	    (assert-true (<= err eps) base err eps)))))))

(define-test issue.130
    (:tag :issues)
  ;; Just verify that file-author works.  In particular "." should
  ;; work and not return NIL.
  (assert-true (file-author "."))
  (assert-true (file-author "bin/build.sh"))
  (assert-true (file-author "tests/안녕하십니까.txt")))
+3 −0
Original line number Diff line number Diff line
The file name of this file is "안녕하십니까.txt" ("Hello" in Korean.)