1 /*
2 clsync - file tree sync utility based on inotify
3
4 Copyright (C) 2013 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "common.h"
21
22 #include "port-hacks.h"
23
24 #include "error.h"
25 #include "malloc.h"
26
27
fd2fpath_malloc(int fd)28 char *fd2fpath_malloc(int fd) {
29 #if __linux__
30 stat64_t st64;
31
32 if(fd <= 0) {
33 error("Invalid file descriptor supplied: fd2fpath_malloc(%i).", fd);
34 errno = EINVAL;
35 return NULL;
36 }
37
38 char *fpath = xmalloc((1<<8) + 2);
39 sprintf(fpath, "/proc/self/fd/%i", fd);
40
41 if(lstat64(fpath, &st64)) {
42 error("Cannot lstat64(\"%s\", st64).", fpath);
43 return NULL;
44 }
45
46 ssize_t fpathlen = st64.st_size;
47
48 if(fpathlen > (1<<8))
49 fpath = xrealloc(fpath, fpathlen+2);
50
51 debug(3, "Getting file path from symlink \"%s\". Path length is: %i.", fpath, fpathlen);
52 if((fpathlen = readlink(fpath, fpath, fpathlen+1)) < 0) {
53 error("Cannot readlink(\"%s\", fpath, bufsize).", fpath);
54 return NULL;
55 }
56 debug(3, "The path is: \"%s\"", fpath);
57
58 fpath[fpathlen] = 0;
59 return fpath;
60 #else
61 critical("Function fd2fpath_malloc() is not supported in this OS");
62 return NULL;
63 #endif
64 }
65
66 /**
67 * @brief Copies file
68 *
69 * @param[in] path_from Source file path
70 * @param[in] path_to Destination file path
71 *
72 * @retval zero Successfully copied
73 * @retval non-zero Got error, while copying
74 *
75 */
76
fileutils_copy(const char * path_from,const char * path_to)77 int fileutils_copy(const char *path_from, const char *path_to) {
78 char buf[BUFSIZ];
79 FILE *from, *to;
80
81 from = fopen(path_from, "r");
82 if(from == NULL) {
83 error("fileutils_copy(\"%s\", \"%s\"): Cannot open file \"%s\" for reading",
84 path_from, path_to, path_from);
85 return errno;
86 }
87
88 to = fopen(path_to, "w");
89 if(to == NULL) {
90 error("fileutils_copy(\"%s\", \"%s\"): Cannot open file \"%s\" for writing",
91 path_from, path_to, path_to);
92 return errno;
93 }
94
95 while(!feof(from)) {
96 int err;
97 size_t r, w;
98
99 r = fread(buf, 1, BUFSIZ, from);
100 if((err=ferror(from))) {
101 error("fileutils_copy(\"%s\", \"%s\"): Cannot read from file \"%s\"",
102 path_from, path_to, path_from);
103 return errno; // CHECK: Is the "errno" should be used in fread() case?
104 }
105
106 w = fwrite(buf, 1, r, to);
107 if((err=ferror(to))) {
108 error("fileutils_copy(\"%s\", \"%s\"): Cannot write to file \"%s\"",
109 path_from, path_to, path_to);
110 return errno; // CHECK: is the "errno" should be used in fwrite() case?
111 }
112 if(r != w) {
113 error("fileutils_copy(\"%s\", \"%s\"): Got error while writing to file \"%s\" (%u != %u)",
114 path_from, path_to, path_to, r, w);
115 return errno; // CHECK: is the "errno" should be used in case "r != w"?
116 }
117 }
118
119 return 0;
120 }
121
122
123 /**
124 * @brief Calculates directory level of a canonized path (actually it just counts "/"-s)
125 *
126 * @param[in] path Canonized path (with realpath())
127 *
128 * @retval zero or prositive Direcory level
129 * @retval negative Got error, while calculation. Error-code is placed to errno.
130 *
131 */
132
fileutils_calcdirlevel(const char * path)133 short int fileutils_calcdirlevel(const char *path) {
134 short int dirlevel = 0;
135 const char *ptr = path;
136
137 if(path == NULL) {
138 error("path is NULL.");
139 errno=EINVAL;
140 return -1;
141 }
142
143 if(*path == 0) {
144 error("path has zero length.");
145 errno=EINVAL;
146 return -2;
147 }
148
149 if(*path != '/') {
150 error("path \"%s\" is not canonized.", path);
151 errno=EINVAL;
152 return -3;
153 }
154
155 while(*(ptr++))
156 if(*ptr == '/')
157 dirlevel++;
158
159 return dirlevel;
160 }
161
162 /**
163 * @brief Combination of mkdirat() and openat()
164 *
165 * @param[in] dir_path Path to directory to create and open
166 @ @param[in] dirfd_parent File descriptor of directory for relative paths
167 @ @param[in] dir_mode Modes for newly created directory (e.g. 750)
168 *
169 * @retval dirfd File descriptor to newly created directory
170 * @retval NULL On error
171 *
172 */
mkdirat_open(const char * const dir_path,int dirfd_parent,mode_t dir_mode)173 int mkdirat_open(const char *const dir_path, int dirfd_parent, mode_t dir_mode) {
174 int dirfd;
175
176 debug(5, "mkdirat(%u, \"%s\", %o)", dirfd_parent, dir_path, dir_mode);
177 if (mkdirat(dirfd_parent, dir_path, dir_mode))
178 return -1;
179
180 debug(5, "openat(%u, \"%s\", %x)", dirfd_parent, dir_path, O_RDWR|O_DIRECTORY|O_PATH);
181 dirfd = openat(dirfd_parent, dir_path, O_RDWR|O_DIRECTORY|O_PATH);
182 if (dirfd == -1)
183 return -1;
184
185 return dirfd;
186 }
187
188