#include #include #include #include #include #include #include #include "misc.h" #include "misc.m" static int file_setperm ( const char *dst, int uid, int gid, int mode, const char *src) // Will use { if (src != NULL){ struct stat st; if (stat(src,&st)!=-1){ if (uid == -1) uid = st.st_uid; if (gid == -1) gid = st.st_gid; if (mode == -1) mode = st.st_mode & 07777; } } int ret = 0; if (uid != -1 || gid != -1) ret = chown (dst,uid,gid); if (ret == 0 && mode != -1) ret = chmod (dst,mode); return ret; } static int file_copy_perm ( const char *src, const char *dst, int uid, int gid, int mode) { int ret = -1; FILE *fin = fopen (src,"r"); if (fin != NULL){ FILE *fout = fopen (dst,"w"); if (fout != NULL){ char buf[10000]; int n; while ((n=fread(buf,1,sizeof(buf),fin))>0) fwrite (buf,1,n,fout); ret = fclose (fout); fclose (fin); ret = file_setperm (dst,uid,gid,mode,src); } } return ret; } /* Create a directory and optionnally force ownership and mode */ int file_mkdir ( const char *dir, int uid, // or -1 int gid, // or -1 int mode, // or -1 const char *src) // Directory to use to copy ownership and permission // (overriden separatly by the above parameter) { int ret = mkdir (dir,0755); if (ret == 0){ ret = file_setperm (dir,uid,gid,mode,src); } return ret; } int file_mkdir ( const char *dir, const char *user, const char *group, int perm) { int ret = -1; struct passwd *p = getpwnam(user); if (p != NULL){ struct group *g = getgrnam(group); if (g != NULL){ ret = file_mkdir (dir,p->pw_uid,g->gr_gid,perm,NULL); } } return ret; } /* Create a sub-directory and all parent directory if needed The directory may be already existing */ int file_mkdirp ( const char *dir, int uid, // or -1 int gid, // or -1 int mode) // or -1 { int ret = 0; if (file_type(dir)==-1){ char pdir[PATH_MAX]; strcpy (pdir,dir); char *pt = strrchr(pdir,'/'); if (pt != NULL){ *pt = '\0'; file_mkdirp (pdir,uid,gid,mode); } ret = file_mkdir (dir,uid,gid,mode,NULL); } return ret; } /* Create a sub-directory and all parent directory if needed The directory may be already existing */ int file_mkdirp ( const char *dir, const char *user, const char *group, int perm) { int ret = -1; struct passwd *p = getpwnam(user); if (p != NULL){ struct group *g = getgrnam(group); if (g != NULL){ ret = file_mkdirp (dir,p->pw_uid,g->gr_gid,perm); } } return ret; } int file_mkdirp ( const char *dir, const char *user, const char *group, const char *perm) { int ret = -1; struct passwd *p = getpwnam(user); if (p != NULL){ struct group *g = getgrnam(group); if (g != NULL){ int fixperm_int; sscanf(perm, "%o", &fixperm_int); ret = file_mkdirp (dir,p->pw_uid,g->gr_gid,fixperm_int); } } return ret; } /* Copy one file. Check if user is allowed Return -1 if any error. */ int file_copy (const char *src, const char *dst) { int ret = -1; if (perm_rootaccess (MSG_U(P_COPYSYSFILES,"to copy system files"))){ if (strcmp(src,dst)==0){ ret = 0; }else{ ret = file_copy_perm (src,dst,-1,-1,-1); } } return ret; } /* Copy a complete directory tree into another optionnally for ownership and mode. If the owner and mode is not provided (-1), those of the source will be used. */ int file_copytree ( const char *src, const char *dst, int uid, int gid, int mode) { int ret = 0; SSTRINGS lst; int n = dir_getlist (src,lst); for (int i=0; iget(); char srcpath[PATH_MAX],dstpath[PATH_MAX]; snprintf (srcpath,sizeof(srcpath)-1,"%s/%s",src,name); snprintf (dstpath,sizeof(dstpath)-1,"%s/%s",dst,name); int type = file_type (srcpath); if (type == 0){ ret = file_copy_perm (srcpath,dstpath,uid,gid,mode); }else if (type == 1){ file_mkdir (dstpath,uid,gid,mode,srcpath); ret = file_copytree (srcpath,dstpath,uid,gid,mode); }else if (type == 2){ // Device special file struct stat st; stat (srcpath,&st); ret = mknod (dstpath,st.st_mode,st.st_rdev); if (ret != -1) ret = file_setperm (dstpath,uid,gid,mode,srcpath); }else if (type == 3){ // Symbolic link char linkpath[PATH_MAX]; int n = readlink (srcpath,linkpath,sizeof(linkpath)-1); if (n == -1){ ret = -1; }else{ linkpath[n] = '\0'; ret = symlink (linkpath,dstpath); } }else{ ret = -1; } } return ret; } /* Follow a symbolic link and extract the effective (real) path realpath will simply contain the original path if it is not a symlink. Return -1 if the link can't be read properly. Return 0 otherwise (even if fpath is not a symlink). */ int file_followlink (const char *fpath, char *realpath) { int ret = 0; strcpy (realpath,fpath); while (file_type(realpath)==3){ char newpath[PATH_MAX]; int len = readlink(realpath,newpath,PATH_MAX-1); if (len==-1){ ret = -1; break; }else{ newpath[len] = '\0'; if (newpath[0] != '/'){ // This is a relative path, we keep the base path // of realpath char basepath[PATH_MAX]; strcpy (basepath,realpath); char *pt = strrchr(basepath,'/'); if (pt != NULL){ *++pt = '\0'; }else{ basepath[0] = '\0'; } if (strlen(basepath) + strlen(newpath) < PATH_MAX){ strcat (basepath,newpath); // We could try to simplify the path by stripping // ../ further, Would it be useful ? strcpy (realpath,basepath); }else{ ret = -1; } }else{ strcpy (realpath,newpath); } } } return ret; } static int file_type (struct stat &st) { int ret = -1; if (S_ISREG(st.st_mode)){ ret = 0; }else if (S_ISDIR(st.st_mode)){ ret = 1; }else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)){ ret = 2; }else if (S_ISLNK(st.st_mode)){ ret = 3; }else if (S_ISFIFO(st.st_mode)){ ret = 4; } return ret; } /* Check the type of a file or directory. If follow is 1, follow symbolic links. Return -1 if the path does not exist. Return 0 if this is a file 1 if this is a directory 2 if this is a device 3 if this is a symbolic link 4 if this is a fifo */ int file_type (const char *path, bool follow) { struct stat st; int ret = -1; if (path[0] == '\0' || strcmp(path,"/")==0){ ret = 1; }else if ((follow || lstat(path,&st)!=-1) && (!follow || stat(path,&st)!=-1)) { ret = file_type (st); } return ret; } int file_type (const char *path) { return file_type(path,false); } /* Check the type of a file or directory. Return -1 if the path does not exist. Return 0 if this is a file 1 if this is a directory 2 if this is a device 3 if this is a symbolic link 4 if this is a fifo This function uses stat instead of lstat */ int file_rtype (const char *path) { struct stat st; int ret = -1; if (path[0] == '\0' || strcmp(path,"/")==0){ ret = 1; }else if (stat(path,&st)!=-1){ ret = file_type (st); } return ret; } /* Check if the file or directory exist. Return true if yes. */ bool file_exist (const char *path) { return file_type (path)!=-1; }