From 2e420db19cab6bf7849db02bf6b99e6bc58c40df Mon Sep 17 00:00:00 2001
From: Warren Dukes <warren.dukes@gmail.com>
Date: Fri, 16 Apr 2004 00:41:56 +0000
Subject: [PATCH] remove directory mtime from db! also, only reReadDB and write
 DB on update if something was actually updated

git-svn-id: https://svn.musicpd.org/mpd/trunk@780 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 TODO            |   4 --
 src/directory.c | 179 +++++++++++++++++++++++++++++++++---------------
 src/ls.c        |   3 +-
 src/ls.h        |   2 +-
 4 files changed, 125 insertions(+), 63 deletions(-)

diff --git a/TODO b/TODO
index 123089429..3d76e2091 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,4 @@
 1) non-blocking (for other clients) update
-	n) mpd command for rereading db
-	o) rewrite update functions to indicate if something was updated, then
-	 	when update process returns, indicate wheater db was updated
-		and should be reread by parent process
 	p) set error: in status when an error occurs during update
 
 2) cleanup main()
diff --git a/src/directory.c b/src/directory.c
index 95f4f9bf2..726eae241 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -59,13 +59,16 @@
 #define DIRECTORY_SEARCH_TITLE		"title"
 #define DIRECTORY_SEARCH_FILENAME	"filename"
 
+#define DIRECTORY_UPDATE_EXIT_NOUPDATE  0
+#define DIRECTORY_UPDATE_EXIT_UPDATE    1
+#define DIRECTORY_UPDATE_EXIT_ERROR     2
+
 typedef List DirectoryList;
 
 typedef struct _Directory {
 	char * utf8name;
 	DirectoryList * subDirectories;
 	SongList * songs;
-	time_t mtime; /* modification time */
 } Directory;
 
 Directory * mp3rootDirectory = NULL;
@@ -107,7 +110,7 @@ Directory * getDirectory(char * name);
 Song * getSongDetails(char * file, char ** shortnameRet, 
 		Directory ** directoryRet);
 
-void updatePath(char * utf8path);
+int updatePath(char * utf8path);
 
 void sortDirectory(Directory * directory);
 
@@ -129,12 +132,20 @@ void directory_sigChldHandler(int pid, int status) {
                                         "non-TERM signal: %i\n",
                                         WTERMSIG(status));
                 }
-		else if(!WIFSIGNALED(status) &&
-				WEXITSTATUS(status)==EXIT_SUCCESS) 
-		{
-			DEBUG("direcotry_sigChldHandler: "
-					"updated db succesffully\n");
-			directory_reReadDB = 1;
+		else if(!WIFSIGNALED(status)) {
+			switch(WEXITSTATUS(status)) 
+		        {
+                        case DIRECTORY_UPDATE_EXIT_UPDATE:
+			        directory_reReadDB = 1;
+			        DEBUG("direcotry_sigChldHandler: "
+					"updated db\n");
+                        case DIRECTORY_UPDATE_EXIT_NOUPDATE:
+			        DEBUG("direcotry_sigChldHandler: "
+					"update exitted succesffully\n");
+                                break;
+                        default:
+                                ERROR("error updating db\n");
+                        }
 		}
 		clearUpdatePid();
 	}
@@ -167,6 +178,7 @@ int updateInit(FILE * fp, List * pathList) {
 	directory_updatePid = fork();
        	if(directory_updatePid==0) {
               	/* child */
+                int dbUpdated = 0;
 		clearPlayerPid();
 	
 		unblockSignals();
@@ -181,19 +193,34 @@ int updateInit(FILE * fp, List * pathList) {
 			ListNode * node = pathList->firstNode;
 
 			while(node) {
-				updatePath(node->key);
+				switch(updatePath(node->key)) {
+                                case 1:
+                                        dbUpdated = 1;
+                                        break;
+                                case 0:
+                                        break;
+                                default:
+                                        exit(DIRECTORY_UPDATE_EXIT_ERROR);
+                                }
 				node = node->nextNode;
 			}
 		}
-		else if(updateDirectory(mp3rootDirectory)<0) exit(EXIT_FAILURE);
+		else {
+                        if((dbUpdated = updateDirectory(mp3rootDirectory))<0) {
+                                exit(DIRECTORY_UPDATE_EXIT_ERROR);
+                        }
+                }
+
+                if(!dbUpdated) exit(DIRECTORY_UPDATE_EXIT_NOUPDATE);
+
 		/* ignore signals since we don't want them to corrupt the db*/
 		ignoreSignals();
 		if(writeDirectoryDB()<0) {
 			ERROR("problems writing music db file, \"%s\"\n",
 					directory_db);
-			exit(EXIT_FAILURE);
+			exit(DIRECTORY_UPDATE_EXIT_ERROR);
 		}
-		exit(EXIT_SUCCESS);
+		exit(DIRECTORY_UPDATE_EXIT_UPDATE);
 	}
 	else if(directory_updatePid < 0) {
 		unblockSignals();
@@ -214,7 +241,7 @@ int updateInit(FILE * fp, List * pathList) {
 	return 0;
 }
 
-Directory * newDirectory(char * dirname, time_t mtime) {
+Directory * newDirectory(char * dirname) {
 	Directory * directory;
 
 	directory = malloc(sizeof(Directory));
@@ -223,8 +250,6 @@ Directory * newDirectory(char * dirname, time_t mtime) {
 	else directory->utf8name = NULL;
 	directory->subDirectories = newDirectoryList();
 	directory->songs = newSongList();
-	if(mtime<0) isDir(dirname,&(directory->mtime));
-	else directory->mtime = mtime;
 
 	return directory;
 }
@@ -271,6 +296,11 @@ void deleteEmptyDirectoriesInDirectory(Directory * directory) {
 	}
 }
 
+/* return values:
+   -1 -> error
+    0 -> no error, but nothing updated
+    1 -> no error, and stuff updated
+ */
 int updateInDirectory(Directory * directory, char * shortname, char * name) {
 	time_t mtime;
 	void * song;
@@ -279,19 +309,24 @@ int updateInDirectory(Directory * directory, char * shortname, char * name) {
 	if(isMusic(name,&mtime)) {
 		if(0==findInList(directory->songs,shortname,&song)) {
 			addToDirectory(directory,shortname,name);
+                        return 1;
 		}
 		else if(mtime!=((Song *)song)->mtime) {
 			LOG("updating %s\n",name);
 			if(updateSongInfo((Song *)song)<0) {
 				removeSongFromDirectory(directory,shortname);
 			}
+                        return 1;
 		}
 	}
-	else if(isDir(name,&mtime)) {
+	else if(isDir(name)) {
 		if(findInList(directory->subDirectories,shortname,(void **)&subDir)) {
-			updateDirectory((Directory *)subDir);
+			if(updateDirectory((Directory *)subDir)>0) return 1;
 		}
-		else addSubDirectoryToDirectory(directory,shortname,name);
+		else {
+                        addSubDirectoryToDirectory(directory,shortname,name);
+                        return 1;
+                }
 	}
 
 	return 0;
@@ -308,6 +343,7 @@ int removeDeletedFromDirectory(Directory * directory) {
 	char * utf8;
 	ListNode * node;
 	ListNode * tmpNode;
+        int ret = 0;
 
 	cwd[0] = '.';
 	cwd[1] = '\0';
@@ -336,10 +372,11 @@ int removeDeletedFromDirectory(Directory * directory) {
 	while(node) {
 		tmpNode = node->nextNode;
 		if(findInList(entList,node->key,&name)) {
-			if(!isDir((char *)name,NULL)) {
+			if(!isDir((char *)name)) {
 				LOG("removing directory: %s\n",(char*)name);
 				deleteFromList(directory->subDirectories,
 						node->key);
+                                ret = 1;
 			}
 		}
 		else {
@@ -347,6 +384,7 @@ int removeDeletedFromDirectory(Directory * directory) {
 			if(directory->utf8name) LOG("%s/",directory->utf8name);
 			LOG("%s\n",node->key);
 			deleteFromList(directory->subDirectories,node->key);
+                        ret = 1;
 		}
 		node = tmpNode;
 	}
@@ -357,17 +395,19 @@ int removeDeletedFromDirectory(Directory * directory) {
 		if(findInList(entList,node->key,(void **)&name)) {
 			if(!isMusic(name,NULL)) {
 				removeSongFromDirectory(directory,node->key);
+                                ret = 1;
 			}
 		}
 		else {
 			removeSongFromDirectory(directory,node->key);
+                        ret = 1;
 		}
 		node = tmpNode;
 	}
 
 	freeList(entList);
 
-	return 0;
+	return ret;
 }
 
 Directory * addDirectoryPathToDB(char * utf8path, char ** shortname) {
@@ -415,61 +455,88 @@ Directory * addParentPathToDB(char * utf8path, char ** shortname) {
 	return (Directory *)parentDirectory;
 }
 
-void updatePath(char * utf8path) {
+/* return values:
+   -1 -> error
+    0 -> no error, but nothing updated
+    1 -> no error, and stuff updated
+ */
+int updatePath(char * utf8path) {
 	Directory * directory;
 	Directory * parentDirectory;
 	Song * song;
 	char * shortname;
 	char * path = sanitizePathDup(utf8path);
+        time_t mtime;
+        int ret = 0;
 
-	if(NULL==path) return;
+	if(NULL==path) return -1;
 
 	/* if path is in the DB try to update it, or else delete it */
 	if((directory = getDirectoryDetails(path,&shortname,
 			&parentDirectory))) 
 	{
 		/* if this update directory is successfull, we are done */
-		if(updateDirectory(directory)==0)
+		if((ret = updateDirectory(directory))>=0)
 		{
 			free(path);
 			sortDirectory(directory);
-			return;
+			return ret;
 		}
 		/* we don't want to delete the root directory */
 		else if(directory == mp3rootDirectory) {
 			free(path);
-			return;
+			return 0;
 		}
 		/* if updateDirectory fials, means we should delete it */
 		else {
 			LOG("removing directory: %s\n",path);
 			deleteFromList(parentDirectory->subDirectories,
 					shortname);
+                        ret = 1;
+                        /* don't return, path maybe a song now*/
 		}
 	}
 	else if((song = getSongDetails(path,&shortname,&parentDirectory))) {
 		/* if this song update is successfull, we are done */
-		if(song && updateSongInfo(song)==0) {
+		if(song && isMusic(song->utf8file,&mtime)) {
 			free(path);
-			return;
+                        if(song->mtime==mtime) return 0;
+                        else if(updateSongInfo(song)==0) return 1;
+                        else {
+                                removeSongFromDirectory(parentDirectory,
+                                                shortname);
+                                return 1;
+                        }
 		}
 		/* if updateDirectory fials, means we should delete it */
-		else removeSongFromDirectory(parentDirectory,shortname);
+		else {
+                        removeSongFromDirectory(parentDirectory,shortname);
+                        ret = 1;
+                        /* don't return, path maybe a directory now*/
+                }
 	}
 
 	/* path not found in the db, see if it actually exists on the fs.
 	 * Also, if by chance a directory was replaced by a file of the same
          * name or vice versa, we need to add it to the db
          */
-	if(isDir(path,NULL) || isMusic(path,NULL)) {
+	if(isDir(path) || isMusic(path,NULL)) {
 		parentDirectory = addParentPathToDB(path,&shortname);
 		addToDirectory(parentDirectory,shortname,path);
 		sortDirectory(parentDirectory);
+                ret = 1;
 	}
 
 	free(path);
+
+        return ret;
 }
 
+/* return values:
+   -1 -> error
+    0 -> no error, but nothing updated
+    1 -> no error, and stuff updated
+ */
 int updateDirectory(Directory * directory) {
 	DIR * dir;
 	char cwd[2];
@@ -477,12 +544,13 @@ int updateDirectory(Directory * directory) {
 	char * s;
 	char * utf8;
 	char * dirname = directory->utf8name;
+        int ret = 0;
 
 	cwd[0] = '.';
 	cwd[1] = '\0';
 	if(dirname==NULL) dirname=cwd;
 
-	removeDeletedFromDirectory(directory);
+	if(removeDeletedFromDirectory(directory)>0) ret = 1;
 
 	if((dir = opendir(rmp2amp(utf8ToFsCharset(dirname))))==NULL) return -1;
 
@@ -500,16 +568,14 @@ int updateDirectory(Directory * directory) {
 			sprintf(s,"%s/%s",directory->utf8name,utf8);
 		}
 		else s = strdup(utf8);
-		updateInDirectory(directory,utf8,s);
+		if(updateInDirectory(directory,utf8,s)>0) ret = 1;
 		free(utf8);
 		free(s);
 	}
 	
 	closedir(dir);
 
-	if(directory->utf8name) isDir(directory->utf8name,&(directory->mtime));
-
-	return 0;
+	return ret;
 }
 
 int exploreDirectory(Directory * directory) {
@@ -557,7 +623,7 @@ int exploreDirectory(Directory * directory) {
 Directory * addSubDirectoryToDirectory(Directory * directory, char * shortname, 
 	char * name) 
 {
-	Directory * subDirectory = newDirectory(name,-1);
+	Directory * subDirectory = newDirectory(name);
 	
 	insertInList(directory->subDirectories,shortname,subDirectory);
 	exploreDirectory(subDirectory);
@@ -566,7 +632,7 @@ Directory * addSubDirectoryToDirectory(Directory * directory, char * shortname,
 }
 
 int addToDirectory(Directory * directory, char * shortname, char * name) {
-	if(isDir(name,NULL)) {
+	if(isDir(name)) {
 		addSubDirectoryToDirectory(directory,shortname,name);
 		return 0;
 	}
@@ -685,7 +751,6 @@ void writeDirectoryInfo(FILE * fp, Directory * directory) {
 	while(node!=NULL) {
 		subDirectory = (Directory *)node->data;
 		myfprintf(fp,"%s%s\n",DIRECTORY_DIR,node->key);
-		myfprintf(fp,"%s%li\n",DIRECTORY_MTIME,(long)subDirectory->mtime);
 		writeDirectoryInfo(fp,subDirectory);
 		node = node->nextNode;
 	}
@@ -703,7 +768,6 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
 	char * key;
 	Directory * subDirectory;
 	char * name;
-	time_t mtime;
 	int strcmpRet;
 	ListNode * nextDirNode = directory->subDirectories->firstNode;
 	ListNode * nodeTemp;
@@ -712,21 +776,20 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
 		if(0==strncmp(DIRECTORY_DIR,buffer,strlen(DIRECTORY_DIR))) {
 			key = strdup(&(buffer[strlen(DIRECTORY_DIR)]));
 			if(myFgets(buffer,bufferSize,fp)<0) {
-				ERROR("Error reading db\n");
-				exit(EXIT_FAILURE);
-			}
-			if(strncmp(DIRECTORY_MTIME,buffer,strlen(DIRECTORY_MTIME))) {
-				ERROR("Error reading db\n");
-				ERROR("%s\n",buffer);
-				exit(EXIT_FAILURE);
-			}
-			mtime = atoi(&(buffer[strlen(DIRECTORY_BEGIN)]));
-			if(myFgets(buffer,bufferSize,fp)<0) {
-				ERROR("Error reading db\n");
+				        ERROR("Error reading db, fgets\n");
 				exit(EXIT_FAILURE);
 			}
+                        /* for compatibility with db's prior to 0.11 */
+			if(0==strncmp(DIRECTORY_MTIME,buffer,
+                                        strlen(DIRECTORY_MTIME))) 
+                        {
+			        if(myFgets(buffer,bufferSize,fp)<0) {
+				        ERROR("Error reading db, fgets\n");
+				        exit(EXIT_FAILURE);
+			        }
+                        }
 			if(strncmp(DIRECTORY_BEGIN,buffer,strlen(DIRECTORY_BEGIN))) {
-				ERROR("Error reading db\n");
+				ERROR("Error reading db at line: %s\n",buffer);
 				exit(EXIT_FAILURE);
 			}
 			name = strdup(&(buffer[strlen(DIRECTORY_BEGIN)]));
@@ -740,17 +803,16 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
 			}
 
 			if(NULL==nextDirNode) {
-				subDirectory = newDirectory(name,mtime);
+				subDirectory = newDirectory(name);
 				insertInList(directory->subDirectories,key,
 						(void *)subDirectory);
 			}
 			else if(strcmpRet == 0) {
 				subDirectory = (Directory *)nextDirNode->data;
-				subDirectory->mtime = mtime;
 				nextDirNode = nextDirNode->nextNode;
 			}
 			else {
-				subDirectory = newDirectory(name,mtime);
+				subDirectory = newDirectory(name);
 				insertInListBeforeNode(
 						directory->subDirectories,
 						nextDirNode,
@@ -817,7 +879,7 @@ int writeDirectoryDB() {
 int readDirectoryDB() {
 	FILE * fp;
 
-	if(!mp3rootDirectory) mp3rootDirectory = newDirectory(NULL,0);
+	if(!mp3rootDirectory) mp3rootDirectory = newDirectory(NULL);
 	while(!(fp=fopen(directory_db,"r")) && errno==EINTR);
 	if(!fp) return -1;
 
@@ -829,7 +891,7 @@ int readDirectoryDB() {
 		int foundVersion = 0;
 
 		if(myFgets(buffer,bufferSize,fp)<0) {
-			ERROR("Error reading db\n");
+			ERROR("Error reading db, fgets\n");
 			exit(EXIT_FAILURE);
 		}
 		if(0==strcmp(DIRECTORY_INFO_BEGIN,buffer)) {
@@ -898,6 +960,11 @@ int readDirectoryDB() {
 	return 0;
 }
 
+/* return values:
+   -1 -> error
+    0 -> no error, but nothing updated
+    1 -> no error, and stuff updated
+ */
 int updateMp3Directory(FILE * fp) {
 	if(updateDirectory(mp3rootDirectory)<0) {
 		ERROR("problems updating music db\n");
@@ -1134,7 +1201,7 @@ unsigned long sumSongTimesIn(FILE * fp, char * name) {
 void initMp3Directory() {
 	struct stat st;
 
-	mp3rootDirectory = newDirectory(NULL,0);
+	mp3rootDirectory = newDirectory(NULL);
 	exploreDirectory(mp3rootDirectory);
 	stats.numberOfSongs = countSongsIn(stderr,NULL);
 	stats.dbPlayTime = sumSongTimesIn(stderr,NULL);
diff --git a/src/ls.c b/src/ls.c
index 556b68d79..6b9b46ed1 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -179,12 +179,11 @@ int hasMp3Suffix(char * utf8file) {
 	return hasSuffix(utf8file,"mp3");
 }
 
-int isDir(char * utf8name, time_t * mtime) {
+int isDir(char * utf8name) {
 	struct stat st;
 
 	if(stat(rmp2amp(utf8ToFsCharset(utf8name)),&st)==0) {
 		if(S_ISDIR(st.st_mode)) {
-			if(mtime) *mtime = st.st_mtime;
 			return 1;
 		}
 	}
diff --git a/src/ls.h b/src/ls.h
index 03cbb8d11..2f724d08f 100644
--- a/src/ls.h
+++ b/src/ls.h
@@ -28,7 +28,7 @@ int lsPlaylists(FILE * fp, char * utf8path);
 
 int isFile(char * utf8file, time_t * mtime);
 
-int isDir(char * utf8name, time_t * mtime);
+int isDir(char * utf8name);
 
 int isPlaylist(char * utf8file);
 
-- 
2.24.1