GRASS Programmer's Manual
6.4.2(2012)
|
00001 00002 /**************************************************************************** 00003 * 00004 * MODULE: GRASS GIS library - copy_dir.c 00005 * AUTHOR(S): Huidae Cho 00006 * PURPOSE: Function to recursively copy a directory 00007 * COPYRIGHT: (C) 2008 by the GRASS Development Team 00008 * 00009 * NOTE: Extracted from general/manage/lib/do_copy.c 00010 * 00011 * This program is free software under the GNU General Public 00012 * License (>=v2). Read the file COPYING that comes with GRASS 00013 * for details. 00014 * 00015 *****************************************************************************/ 00016 00017 #include <stdio.h> 00018 #include <errno.h> 00019 #include <string.h> 00020 00021 #include <grass/gis.h> 00022 00023 #include <fcntl.h> 00024 #include <unistd.h> 00025 #include <dirent.h> 00026 #include <sys/types.h> 00027 #include <sys/stat.h> 00028 00029 /* RULE: 00030 * 1. If destination does not exist, copy source to destination as expected. 00031 * 2. If destination already exists and it's a file, destination will be 00032 * deleted first and apply RULE 1. 00033 * 3. If destination already exists which is a directory and source is a file, 00034 * try to copy source to destination directory. 00035 * 4. If destination already exists which is a directory and source is also a 00036 * directory, try to copy all contents in source to destination directory. 00037 * 00038 * This rule is designed according to general/manage/lib/copy.sh. 00039 * 00040 * POSSIBLE CASES: 00041 * if src is a file: 00042 * if dst does not exist: 00043 * copy src to dst RULE 1 00044 * if dst is a file: 00045 * delete dst and copy src to dst RULE 2 00046 * if dst is a directory: 00047 * try recursive_copy(src, dst/src) RULE 3 00048 * if src is a directory: 00049 * if dst does not exist: 00050 * copy src to dst RULE 1 00051 * if dst is a file: 00052 * delete dst and copy src to dst RULE 2 00053 * if dst is a directory: 00054 * try RULE 4 00055 * for i in `ls src` 00056 * do 00057 * recursive_copy(src/$i, dst/$i) 00058 * done 00059 * 00060 * RETURN: 0 if successful, otherwise 1 00061 */ 00062 00063 int G_recursive_copy(const char *src, const char *dst) 00064 { 00065 DIR *dirp; 00066 struct stat sb; 00067 00068 if (G_lstat(src, &sb) < 0) 00069 return 1; 00070 00071 /* src is a file */ 00072 if (!S_ISDIR(sb.st_mode)) { 00073 char buf[4096]; 00074 int fd, fd2; 00075 size_t len, len2; 00076 00077 if (G_lstat(dst, &sb) == 0 && S_ISDIR(sb.st_mode)) { 00078 char path[GPATH_MAX]; 00079 const char *p = strrchr(src, '/'); 00080 00081 /* src => dst/src */ 00082 sprintf(path, "%s/%s", dst, (p ? p + 1 : src)); 00083 return G_recursive_copy(src, path); 00084 } 00085 00086 /* src => dst */ 00087 if ((fd = open(src, O_RDONLY)) < 0) 00088 return 1; 00089 00090 if ((fd2 = 00091 open(dst, O_CREAT | O_TRUNC | O_WRONLY, 00092 sb.st_mode & 0777)) < 0) { 00093 close(fd); 00094 return 1; 00095 } 00096 00097 while ((len = read(fd, buf, sizeof(buf))) > 0) { 00098 while (len && (len2 = write(fd2, buf, len)) >= 0) 00099 len -= len2; 00100 } 00101 00102 close(fd); 00103 close(fd2); 00104 00105 return 0; 00106 } 00107 00108 /* src is a directory */ 00109 if (G_lstat(dst, &sb) < 0) { 00110 if (G_mkdir(dst)) 00111 return 1; 00112 } 00113 else 00114 /* if dst already exists and it's a file, try to remove it */ 00115 if (!S_ISDIR(sb.st_mode)) { 00116 if (remove(dst) < 0 || G_mkdir(dst) < 0) 00117 return 1; 00118 } 00119 00120 dirp = opendir(src); 00121 if (!dirp) 00122 return 1; 00123 00124 for (;;) { 00125 char path[GPATH_MAX], path2[GPATH_MAX]; 00126 struct dirent *dp = readdir(dirp); 00127 00128 if (!dp) 00129 break; 00130 00131 /* do not copy hidden files */ 00132 if (dp->d_name[0] == '.') 00133 continue; 00134 00135 sprintf(path, "%s/%s", src, dp->d_name); 00136 sprintf(path2, "%s/%s", dst, dp->d_name); 00137 00138 if (G_recursive_copy(path, path2) != 0) 00139 return 1; 00140 } 00141 00142 closedir(dirp); 00143 00144 return 0; 00145 }