/* * Create all the directories in the given path. Path must be non-const. Trailing '/' characters are removed. */ int bpc_path_create(char *path) { char *p = path; STRUCT_STAT st; int levels = 0; if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_path_create(%s)\n", path); /* * check if it exists already */ if ( !stat(path, &st) && S_ISDIR(st.st_mode) ) return 0; /* * We walk up until we find the deepest level directory that exists. * First remove trailing slashes. */ p = path + strlen(path); while ( p > path && p[-1] == '/' ) p--; if ( *p == '/' ) *p = '\0'; while ( p > path ) { while ( p > path && p[-1] != '/' ) p--; while ( p > path && p[-1] == '/' ) p--; if ( *p == '/' ) { *p = '\0'; levels++; if ( !stat(path, &st) && S_ISDIR(st.st_mode) ) break; } } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_create: found that %s exists (%d levels up)\n", path, levels); /* * We have removed levels '/' characters from path. Replace each one and create the directory. */ while ( levels-- > 0 ) { p = path + strlen(path); *p = '/'; if ( mkdir(path, ACCESSPERMS) < 0 && errno != EEXIST) { bpc_logErrf("bpc_path_create: can't create %s (errno %d)\n", path, errno); return -1; } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_create: created %s\n", path); } return 0; }
/* * Given a backup path, split it into the directory, file name, and path to the directory (starting * with the share name, ie: relative to ac->backupTopDir). * * splitPath will strip initial "./" and trailing "/." or "/" before splitting the path, but isn't * capable of handling paths with "/." in the middle, or ".." anywhere. */ static void splitPath(bpc_attribCache_info *ac, char *dir, char *fileName, char *attribPath, char *path) { char *dirOrig = dir; char fullPath[BPC_MAXPATHLEN]; size_t pathLen; /* * remove initial "./" */ while ( path[0] == '.' && path[1] == '/' ) { path += 2; while ( path[0] == '/' ) path++; } /* * if this is a relative path, prepend ac->currentDir (provided ac->currentDir is set) */ if ( path[0] != '/' && ac->currentDir[0] ) { snprintf(fullPath, BPC_MAXPATHLEN, "%s/%s", ac->currentDir, path); path = fullPath; } /* * strip trailing "/." or "/" */ pathLen = strlen(path); while ( (pathLen > 1 && path[pathLen - 2] == '/' && path[pathLen - 1] == '.') || (pathLen > 0 && path[pathLen - 1] == '/') ) { if ( path != fullPath ) { strncpy(fullPath, path, BPC_MAXPATHLEN); path = fullPath; } if ( path[pathLen - 1] == '/' ) { pathLen -= 1; } else { pathLen -= 2; } path[pathLen] = '\0'; if ( BPC_LogLevel >= 9 ) bpc_logMsgf("splitPath: trimming path = '%s'\n", path); } if ( !path[0] || (!path[1] && (path[0] == '.' || path[0] == '/')) ) { strcpy(fileName, ac->shareNameUM); strcpy(dir, "/"); strcpy(attribPath, "/attrib"); } else { char *p; int dirLen = BPC_MAXPATHLEN - ac->shareNameLen; strcpy(dir, ac->shareName); dir += strlen(dir); if ( (p = strrchr(path, '/')) ) { if ( *path != '/' ) { *dir++ = '/'; dirLen--; *dir = '\0'; } strcpy(fileName, p+1); *p = '\0'; bpc_fileNameMangle(dir, dirLen, path); *p = '/'; } else { strcpy(fileName, path); } snprintf(attribPath, BPC_MAXPATHLEN, "%s/attrib", dirOrig); } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("splitPath: returning dir = '%s', fileName = '%s', attrib = '%s' from path = '%s'\n", dirOrig, fileName, attribPath, path); }
/* * Remove all the files below path (if a directory) and path itself. Deduct reference counts * for every attrib file removed. * * Note that inodes are *not* updated, even in cases where nlinks > 0. */ int bpc_path_remove(char *path, int compress) { char filePath[BPC_MAXPATHLEN]; STRUCT_STAT st; DIR *dir; struct dirent *dp; int errorCnt = 0; size_t dirListSize = 0, dirListLen = 0; char *dirList = NULL, *dirListP; if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_path_remove(%s)\n", path); if ( !(dir = opendir(path)) ) { unlink(path); return errorCnt; } while ( (dp = readdir(dir)) ) { if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") ) continue; snprintf(filePath, sizeof(filePath), "%s/%s", path, dp->d_name); if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_path_remove: removing %s\n", filePath); if ( stat(filePath, &st) ) { /* * hmmm. stat failed - just try to remove it */ unlink(filePath); continue; } if ( S_ISDIR(st.st_mode) ) { /* * To avoid recursing with dir still open (consuming an open fd), remember all the dirs * and recurse after we close dir. */ if ( !dirList ) { dirListSize = 4096; if ( !(dirList = malloc(dirListSize)) ) { bpc_logErrf("bpc_path_refCountAll: can't allocate %u bytes\n", (unsigned)dirListSize); return ++errorCnt; } } if ( dirListLen + strlen(dp->d_name) + 1 >= dirListSize ) { dirListSize = dirListSize * 2 + strlen(dp->d_name); if ( !(dirList = realloc(dirList, dirListSize)) ) { bpc_logErrf("bpc_path_refCountAll: can't reallocate %u bytes\n", (unsigned)dirListSize); return ++errorCnt; } } strcpy(dirList + dirListLen, dp->d_name); dirListLen += strlen(dp->d_name) + 1; } else { /* * if this is an attrib file, we need to read it and deduct the reference counts. */ if ( !strncmp(dp->d_name, "attrib", 6) ) { bpc_attrib_dir dir; bpc_attrib_dirInit(&dir, compress); if ( bpc_attrib_dirRead(&dir, NULL, filePath, 0) ) { bpc_logErrf("bpc_path_remove: can't read attrib file %s\n", filePath); errorCnt++; } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_remove: adjusting ref counts from attrib file %s\n", filePath); if ( !unlink(filePath) ) { /* * Only reduce the ref counts if we succeeded in removing the attrib file */ bpc_attrib_dirRefCount(&dir, -1); } bpc_attrib_dirDestroy(&dir); } else { if ( unlink(filePath) ) errorCnt++; } } } closedir(dir); /* * Now visit the subdirs we have saved above. */ if ( dirList ) { for ( dirListP = dirList ; dirListP < dirList + dirListLen ; dirListP += strlen(dirListP) + 1 ) { snprintf(filePath, sizeof(filePath), "%s/%s", path, dirListP); errorCnt += bpc_path_remove(filePath, compress); } free(dirList); } if ( rmdir(path) ) errorCnt++; return errorCnt; }