#include <sys/types.h>
+#include <sys/file.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <sys/file.h>
+#include <sys/time.h>
#include <unistd.h>
+#include <utime.h>
#include <stdbool.h>
#include <stdlib.h>
#include <fcntl.h>
*/
struct dir_node {
pnode_t node;
+ struct utimbuf times;
size_t size, namelen;
int flags;
char name[PATH_MAX];
static bool dir_valid(char *);
static bool dir_make(const char *, const char *);
static int dir_open(list_t *, const char *, bool);
-static void dir_close(list_t *);
+static void dir_close(list_t *, bool);
static int tree_open(list_t *, const char *, bool);
static int tree_open_r(list_t *, const char *, bool);
static void tree_close(list_t *, bool);
break;
}
(void) closedir(dptr);
- dir_close(dir);
+ dir_close(dir, FALSE);
return error;
}
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.rfl.%d", dirpath,
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.locl", dirpath);
(void) rmdir(buf);
(void) closedir(dptr);
- dir_close(dir);
+ dir_close(dir, FALSE);
return E_PERM;
}
(void) close(fd);
(void) fprintf(stderr, "dir_open(%s) - lstat(%s) - (%s)",
dirpath, buf, strerror(errno));
(void) closedir(dptr);
- dir_close(dir);
+ dir_close(dir, FALSE);
if (locking) {
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.rfl.%d",
dirpath, (int)pid);
/* Release everything cleanly */
(void) fprintf(stderr, "dir_open() - Out of memory\n");
(void) closedir(dptr);
- dir_close(dir);
+ dir_close(dir, FALSE);
if (locking) {
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.rfl.%d",
dirpath, (int)pid);
* files already the value may in fact fit safely into an ssize_t.
*/
dnode->size = (size_t)st.st_size;
+ dnode->times.actime = st.st_atime;
+ dnode->times.modtime = st.st_mtime;
dnode->flags = flags;
dnode->namelen = mm_strncpy(dnode->name, buf, PATH_MAX - 1);
DLIST_APPEND(dir, (node_t *)dnode);
* initialized. Safe to use on empty lists, as long as they at least have
* previously been initialized once using DLIST_INIT().
*/
-static void dir_close(list_t *dir)
+static void dir_close(list_t *dir, bool timefix)
{
struct dir_node *dnode, *tmp;
*/
for (dnode = DLIST_TOP(dir); dnode != NULL; dnode = tmp) {
tmp = DLIST_NEXT(dnode);
+ if (timefix) {
+ if (utime(dnode->name, &dnode->times) == -1)
+ (void) fprintf(stderr, "dir_close() - utime(%s)\n",
+ dnode->name);
+ }
(void) pool_free((pnode_t *)dnode);
}
DLIST_INIT(dir);
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.lock", dirpath);
(void) rmdir(buf);
}
- dir_close(&dir);
+ dir_close(&dir, FALSE);
tree_close(tree, locking);
return E_NOMEM;
}
} else {
- dir_close(&dir);
+ dir_close(&dir, FALSE);
return error;
}
}
-/* Releases all successfully locked directories in the specified tree, as well
- * as all memory resources in use to cache it's filenames. The tree must
- * previously have been loaded using tree_open(). The tree_pool pool_t must
- * previously have been initialized.
+/* Releases all successfully locked directories in the specified tree, apply
+ * their timestamps to reflect the originals, and free all memory resources
+ * in use to cache their filenames.
+ * The tree must previously have been loaded using tree_open(). The tree_pool
+ * pool_t must previously have been initialized.
*/
static void tree_close(list_t *tree, bool locking)
{
/* Can't use DLIST_FOREACH() as we're also freeing nodes */
for (tnode = DLIST_TOP(tree); tnode != NULL; tnode = tmp) {
tmp = DLIST_NEXT(tnode);
- dir_close(&tnode->dir);
if (locking) {
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.rfl.%d", tnode->name,
(int)pid);
(void) snprintf(buf, PATH_MAX - 1, "%s/#cvs.lock", tnode->name);
(void) rmdir(buf);
}
+ /*
+ * We unfortunately need to update timestamps after unlocking the
+ * directory by the above deletions.
+ */
+ dir_close(&tnode->dir, TRUE);
(void) pool_free((pnode_t *)tnode);
}
DLIST_INIT(tree);
}
if (newcnt == oldcnt) {
/* There obviously is a problem here, stop iterating. */
+ if (newcnt != 0)
+ (void) fprintf(stderr,
+ "tree_delete() - directory count %ld not decreasing\n",
+ newcnt);
break;
}
}