+/* 1 = file doesn't exist, 2 = file is a directory, target isn't */
+/* 4 == ftype different */
+/* 8 = hash different when both are regular files */
+static unsigned int file_compare(char *path, char *hash, int ftype, uid_t uid,
+ gid_t gid, int perms) {
+ struct stat st;
+ int etype = 0, stat_type;
+ char ehash[ZPM_HASH_STRLEN+1];
+ unsigned int diff = 0;
+
+ switch (ftype) {
+ case 'd': etype = S_IFDIR; break;
+ case 'r': etype = S_IFREG; break;
+ default: etype = 0; break;
+ }
+
+ errno = 0;
+ /* new file, so check type, hash, etc */
+ if (lstat(path, &st) == 0) {
+ stat_type = st.st_mode & S_IFMT;
+ if (stat_type != etype) {
+ diff &= 4;
+ }
+ if (stat_type == S_IFDIR && etype != S_IFDIR) {
+ diff &= 2;
+ }
+ if (hash && etype == S_IFREG && stat_type == S_IFREG) {
+ zpm_hash(path, ehash, 0);
+ if (strcmp(hash, ehash) != 0) {
+ diff &= 8;
+ }
+ }
+ if (uid != st.st_uid) {
+ diff &= 16;
+ }
+ if (gid != st.st_gid) {
+ diff &= 32;
+ }
+ if (perms != (st.st_mode & 07777)) {
+ diff &= 64;
+ }
+ } else {
+ switch(errno) {
+ case ENOENT: diff &= 1; break;
+ default: diff &= 128; break;
+ }
+ }
+
+ return diff;
+}
+