This repository has been archived by the owner on May 9, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
myio.c
311 lines (256 loc) · 7.43 KB
/
myio.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
Weborf
Copyright (C) 2010-2020 Salvo "LtWorf" Tomaselli
Weborf is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
@author Salvo "LtWorf" Tomaselli <[email protected]>
*/
#include "options.h"
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
#include "instance.h"
#include "types.h"
#include "myio.h"
#ifdef HAVE_LIBSSL
/*
* Does a write to an fd_t
*
* If there is an ssl object attached, it will do an ssl write,
* otherwise it will do a normal write.
*/
int myio_write(fd_t fd, const void *buf, size_t count) {
if (fd.ssl)
return SSL_write(fd.ssl, buf, count);
return write(fd.fd, buf, count);
}
/**
* Does a read from an fd_t.
*
* If there is an ssl object attached, it will do an ssl read,
* otherwise it will do a normal read.
*/
int myio_read(fd_t fd, void *buf, size_t count) {
if (fd.ssl)
return SSL_read(fd.ssl, buf, count);
return read(fd.fd, buf, count);
}
#endif
/**
Copies count bytes from the file descriptor "from" to the
file descriptor "to".
It is possible to use lseek on the descriptors before calling
this function.
Will not close any descriptor
*/
int fd_copy(fd_t from, fd_t to, off_t count) {
char *buf=malloc(FILEBUF);//Buffer to read from file
int reads,wrote;
if (buf==NULL) {
#ifdef SERVERDBG
syslog(LOG_CRIT,"Not enough memory to allocate buffers");
#endif
return ERR_NOMEM; //If no memory is available
}
//Sends file
while (count>0 && (reads=myio_read(from, buf, FILEBUF<count ? FILEBUF : count)) > 0) {
if (reads == 0) { // Descriptor is over
return ERR_NODATA;
}
count -= reads;
wrote = myio_write(to, buf, reads);
if (wrote != reads) { //Error writing to the descriptor
#ifdef SOCKETDBG
syslog(LOG_ERR, "error writing to the file descriptor");
#endif
break;
}
}
free(buf);
return 0;
}
/**
Returns true if the specified file exists
*/
bool file_exists(char *file) {
return access(file, R_OK) == 0;
}
/**
Deletes a directory and its content.
This function is something like rm -rf
dir is the directory to delete
file is a buffer. Allocated outside because it
will be reused by every recoursive call.
Its size is file_s
Returns 0 on success
*/
int dir_remove(char * dir) {
/*
If it is a file, removes it
Otherwise list the directory's content,
then do a recoursive call and do
rmdir on self
*/
if (unlink(dir)==0)
return 0;
DIR *dp = opendir(dir); //Open dir
struct dirent *entry;
if (dp == NULL) {
return 1;
}
char*file=malloc(PATH_LEN);//Buffer for path
if (file==NULL)
return ERR_NOMEM;
//Cycles trough dir's elements
while ((entry=readdir(dp)) != NULL) { //Cycles trough dir's elements
//skips dir . and .. but not all hidden files
if (entry->d_name[0]=='.' && (entry->d_name[1]==0 || (entry->d_name[1]=='.' && entry->d_name[2]==0)))
continue;
snprintf(file, PATH_LEN, "%s/%s", dir, entry->d_name);
dir_remove(file);
}
closedir(dp);
free(file);
return rmdir(dir);
}
#ifdef WEBDAV
/**
Moves a file. If it is on the same partition it will create a new link and delete the previous link.
Otherwise it will create a new copy and delete the old one.
Returns 0 on success.
*/
int file_move(char* source, char* dest) {
int retval=rename(source,dest);
//Not the same device, doing a normal copy
if (retval==-1 && errno==EXDEV) {
retval=file_copy(source,dest);
if (retval==0)
unlink(source);
}
return retval;
}
/**
Copies a file into another file
Returns 0 on success
*/
int file_copy(char* source, char* dest) {
int fd_from=-1;
int fd_to=-1;
ssize_t read_,write_;
int retval=0;
char *buf=NULL;
//Open destination file
if ((fd_to=open(dest,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))<0) {
retval=ERR_FORBIDDEN;
goto escape;
}
if ((fd_from=open(source,O_RDONLY | O_LARGEFILE))<0) {
retval = ERR_FILENOTFOUND;
goto escape;
}
buf=malloc(FILEBUF);//Buffer to read from file
if (buf==NULL) {
retval= ERR_NOMEM;
goto escape;
}
while ((read_=read(fd_from,buf,FILEBUF))>0) {
write_=write(fd_to,buf,read_);
if (write_!=read_) {
retval= ERR_BRKPIPE;
break;
}
}
escape:
free(buf);
if (fd_from>=0) close(fd_from);
if (fd_to>=0) close(fd_to);
return retval;
}
/**This function copies a directory.
The destination directory will be created and
will be filled with the same content of the source directory
Returns 0 on success
*/
int dir_copy (char* source, char* dest) {
return dir_move_copy(source,dest,COPY);
}
/**This function moves a directory.
The destination directory will be created and
will be filled with the same content of the source directory.
Then, the source directory will be deleted.
Returns 0 on success
*/
int dir_move(char* source, char* dest) {
int retval;
if ((retval=rename(source,dest))==0) {
return 0;
} else if (retval==-1 && errno==EXDEV) {
return dir_move_copy(source,dest,MOVE);
} else {
return 1;
}
}
/**
Moves or copies a directory, depending on the method used
Returns 0 on success
*/
int dir_move_copy (char* source, char* dest,int method) {
struct stat f_prop; //File's property
int retval=0;
if (mkdir(dest,S_IRWXU | S_IRWXG | S_IRWXO)!=0) {//Attemps to create destination directory
return ERR_FORBIDDEN;
}
DIR *dp = opendir(source); //Open dir
struct dirent *entry;
int return_code;
if (dp == NULL) {
return ERR_FILENOTFOUND;
}
char*src_file=malloc(PATH_LEN*2);//Buffer for path
if (src_file==NULL)
return ERR_NOMEM;
char* dest_file=src_file+PATH_LEN;
//Cycles trough dir's elements
while ((entry=readdir(dp)) != NULL) {
//skips dir . and .. but not all hidden files
if (entry->d_name[0]=='.' && (entry->d_name[1]==0 || (entry->d_name[1]=='.' && entry->d_name[2]==0)))
continue;
snprintf(src_file,PATH_LEN,"%s/%s",source, entry->d_name);
snprintf(dest_file,PATH_LEN,"%s/%s",dest, entry->d_name);
stat(src_file, &f_prop);
if (S_ISDIR(f_prop.st_mode)) {//Directory
retval=dir_move_copy(src_file,dest_file,method);
} else {//File
if (method==MOVE) {
retval=file_move(src_file,dest_file);
} else {
retval=file_copy(src_file,dest_file);
}
}
if (retval!=0)
goto escape;
}
escape:
closedir(dp);
free(src_file);
//Removing directory after that its content has been moved
if (retval==0 && method==MOVE) {
return rmdir(source);
}
return retval;
}
#endif