Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include <basics.h>
28 : #include "giofuncP.h"
29 : #include <gfile.h>
30 : #include "string.h"
31 : #include <ustring.h>
32 : #include <sys/types.h>
33 : #include <sys/stat.h>
34 : #include <unistd.h>
35 : #include <dirent.h>
36 : #include <errno.h>
37 :
38 : /* the initial space is so that these guys will come first in ordered error */
39 : /* lists in the file chooser */
40 : static unichar_t err401[] = { ' ','U','n','a','u','t','h','o','r','i','z','e','d', '\0' };
41 : static unichar_t err403[] = { ' ','F','o','r','b','i','d','d','e','n', '\0' };
42 : static unichar_t err404[] = { ' ','N','o','t',' ','F','o','u','n','d', '\0' };
43 : static unichar_t err405[] = { ' ','M','e','t','h','o','d',' ','N','o','t',' ','A','l','l','o','w','e','d', '\0' };
44 : static unichar_t err406[] = { ' ','N','o','t',' ','A','c','c','e','p','t','a','b','l','e', '\0' };
45 : static unichar_t err409[] = { ' ','C','o','n','f','l','i','c','t', '\0' };
46 : static unichar_t err412[] = { ' ','P','r','e','c','o','n','d','i','t','i','o','n',' ','F','a','i','l','e','d', '\0' };
47 : static unichar_t err414[] = { ' ','R','e','q','u','e','s','t','-','U','R','I',' ','T','o','o',' ','L','o','n','g', '\0' };
48 : static unichar_t err500[] = { ' ','I','n','t','e','r','n','a','l',' ','S','e','r','v','e','r',' ','E','r','r','o','r', '\0' };
49 :
50 0 : void _GIO_reporterror(GIOControl *gc, int errn) {
51 :
52 0 : uc_strncpy(gc->status,strerror(errn),sizeof(gc->status)/sizeof(unichar_t));
53 :
54 0 : if ( errn==ENOENT || (gc->gf!=gf_dir && errn==ENOTDIR) ) {
55 0 : gc->return_code = 404;
56 0 : gc->error = err404;
57 0 : } else if ( errn==EACCES || errn==EPERM ) {
58 0 : gc->return_code = 401;
59 0 : gc->error = err401;
60 0 : } else if ( errn==EROFS || errn==ENOTEMPTY || errn==EBUSY ) {
61 0 : gc->return_code = 403;
62 0 : gc->error = err403;
63 0 : } else if ( errn==ENOTDIR || errn==EISDIR ) {
64 0 : gc->return_code = 405;
65 0 : gc->error = err405;
66 0 : } else if ( errn==EINVAL ) {
67 0 : gc->return_code = 406;
68 0 : gc->error = err406;
69 0 : } else if ( errn==EEXIST ) {
70 0 : gc->return_code = 409;
71 0 : gc->error = err409;
72 0 : } else if ( errn==ENOSPC || errn==EXDEV || errn==EMLINK) {
73 0 : gc->return_code = 412;
74 0 : gc->error = err412;
75 0 : } else if ( errn==ENAMETOOLONG ) {
76 0 : gc->return_code = 414;
77 0 : gc->error = err414;
78 : } else {
79 0 : gc->return_code = 500;
80 0 : gc->error = err500;
81 : }
82 0 : gc->done = true;
83 0 : (gc->receiveerror)(gc);
84 0 : }
85 :
86 0 : static void _gio_file_dir(GIOControl *gc,char *path) {
87 : DIR *dir;
88 : struct dirent *ent;
89 0 : GDirEntry *head=NULL, *last=NULL, *cur;
90 : char *buffer, *ept, *temp;
91 : struct stat statb;
92 :
93 0 : dir = opendir(path);
94 0 : if ( dir==NULL ) {
95 0 : _GIO_reporterror(gc,errno);
96 0 : return;
97 : }
98 :
99 0 : buffer = (char *) malloc(strlen(path)+FILENAME_MAX+3);
100 0 : strcpy(buffer,path);
101 0 : ept = buffer+strlen(buffer);
102 0 : if ( ept[-1]!='/' )
103 0 : *ept++ = '/';
104 :
105 0 : while (( ent = readdir(dir))!=NULL ) {
106 0 : cur = (GDirEntry *) calloc(1,sizeof(GDirEntry));
107 0 : cur->name = def2u_copy(ent->d_name);
108 0 : strcpy(ept,ent->d_name);
109 0 : stat(buffer,&statb);
110 0 : cur->hasdir = cur->hasexe = cur->hasmode = cur->hassize = cur->hastime = true;
111 0 : cur->size = statb.st_size;
112 0 : cur->mode = statb.st_mode;
113 0 : cur->modtime = statb.st_mtime;
114 0 : cur->isdir = S_ISDIR(cur->mode);
115 0 : cur->isexe = !cur->isdir && (cur->mode & 0100);
116 0 : temp = NULL;
117 : // Things go badly if we open a pipe or a device. So we don't.
118 : #ifdef __MINGW32__
119 : //Symlinks behave differently on Windows and are transparent, so no S_ISLNK.
120 : if (S_ISREG(statb.st_mode) || S_ISDIR(statb.st_mode)) {
121 : #else
122 0 : if (S_ISREG(statb.st_mode) || S_ISDIR(statb.st_mode) || S_ISLNK(statb.st_mode)) {
123 : #endif
124 : // We look at the file and try to determine a MIME type.
125 0 : if ( (temp=GIOguessMimeType(buffer)) || (temp=GIOGetMimeType(buffer)) ) {
126 0 : cur->mimetype = u_copy(c_to_u(temp));
127 0 : free(temp);
128 : }
129 : }
130 0 : if ( last==NULL )
131 0 : head = last = cur;
132 : else {
133 0 : last->next = cur;
134 0 : last = cur;
135 : }
136 : }
137 : #if __CygWin
138 : /* Under cygwin we should give the user access to /cygdrive, even though */
139 : /* a diropen("/") will not find it */
140 : if ( strcmp(path,"/")==0 ) {
141 : cur = (GDirEntry *) calloc(1,sizeof(GDirEntry));
142 : cur->name = def2u_copy("cygdrive");
143 : strcpy(ept,"cygdrive");
144 : stat(buffer,&statb);
145 : cur->hasdir = cur->hasexe = cur->hasmode = cur->hassize = cur->hastime = true;
146 : cur->size = statb.st_size;
147 : cur->mode = statb.st_mode;
148 : cur->modtime = statb.st_mtime;
149 : cur->isdir = S_ISDIR(cur->mode);
150 : cur->isexe = !cur->isdir && (cur->mode & 0100);
151 : if ( last==NULL )
152 : head = last = cur;
153 : else {
154 : last->next = cur;
155 : last = cur;
156 : }
157 : }
158 : #endif
159 0 : closedir(dir);
160 0 : free(buffer);
161 0 : gc->iodata = head;
162 0 : gc->direntrydata = true;
163 0 : gc->return_code = 200;
164 0 : gc->done = true;
165 0 : (gc->receivedata)(gc);
166 : }
167 :
168 0 : static void _gio_file_statfile(GIOControl *gc,char *path) {
169 : GDirEntry *cur;
170 : struct stat statb;
171 :
172 0 : if ( stat(path,&statb)==-1 ) {
173 0 : _GIO_reporterror(gc,errno);
174 : } else {
175 0 : cur = (GDirEntry *) calloc(1,sizeof(GDirEntry));
176 0 : cur->name = uc_copy(GFileNameTail(path));
177 0 : cur->hasdir = cur->hasexe = cur->hasmode = cur->hassize = cur->hastime = true;
178 0 : cur->size = statb.st_size;
179 0 : cur->mode = statb.st_mode;
180 0 : cur->modtime = statb.st_mtime;
181 0 : cur->isdir = S_ISDIR(cur->mode);
182 0 : cur->isexe = !cur->isdir && (cur->mode & 0100);
183 0 : gc->iodata = cur;
184 0 : gc->direntrydata = true;
185 0 : gc->return_code = 200;
186 0 : gc->done = true;
187 0 : (gc->receivedata)(gc);
188 : }
189 0 : }
190 :
191 0 : static void _gio_file_delfile(GIOControl *gc,char *path) {
192 0 : if ( unlink(path)==-1 ) {
193 0 : _GIO_reporterror(gc,errno);
194 : } else {
195 0 : gc->return_code = 201;
196 0 : gc->done = true;
197 0 : (gc->receivedata)(gc);
198 : }
199 0 : }
200 :
201 0 : static void _gio_file_deldir(GIOControl *gc,char *path) {
202 0 : if ( rmdir(path)==-1 ) {
203 0 : _GIO_reporterror(gc,errno);
204 : } else {
205 0 : gc->return_code = 201;
206 0 : gc->done = true;
207 0 : (gc->receivedata)(gc);
208 : }
209 0 : }
210 :
211 0 : static void _gio_file_renamefile(GIOControl *gc,char *path, char *topath) {
212 0 : if ( rename(path,topath)==-1 ) {
213 0 : _GIO_reporterror(gc,errno);
214 : } else {
215 0 : gc->return_code = 201;
216 0 : gc->done = true;
217 0 : (gc->receivedata)(gc);
218 : }
219 0 : }
220 :
221 0 : static void _gio_file_mkdir(GIOControl *gc,char *path) {
222 0 : if ( GFileMkDir(path)==-1 ) {
223 0 : _GIO_reporterror(gc,errno);
224 : } else {
225 0 : gc->return_code = 201;
226 0 : gc->done = true;
227 0 : (gc->receivedata)(gc);
228 : }
229 0 : }
230 :
231 0 : void _GIO_localDispatch(GIOControl *gc) {
232 0 : char *path = u2def_copy(gc->path);
233 : char *topath;
234 :
235 0 : switch ( gc->gf ) {
236 : case gf_dir:
237 0 : _gio_file_dir(gc,path);
238 0 : break;
239 : case gf_statfile:
240 0 : _gio_file_statfile(gc,path);
241 0 : break;
242 : case gf_mkdir:
243 0 : _gio_file_mkdir(gc,path);
244 0 : break;
245 : case gf_delfile:
246 0 : _gio_file_delfile(gc,path);
247 0 : break;
248 : case gf_deldir:
249 0 : _gio_file_deldir(gc,path);
250 0 : break;
251 : case gf_renamefile:
252 0 : topath = cu_copy(gc->topath);
253 0 : _gio_file_renamefile(gc,path,topath);
254 0 : free(topath);
255 0 : break;
256 : default:
257 0 : break;
258 : }
259 0 : free(path);
260 0 : }
261 :
262 : /* pathname preceded by "file://" just strip off the "file://" and treat as a */
263 : /* filename */
264 0 : void *_GIO_fileDispatch(GIOControl *gc) {
265 : char *username, *password, *host, *path, *topath;
266 : int port;
267 :
268 0 : path = _GIO_decomposeURL(gc->path,&host,&port,&username,&password);
269 0 : free(host); free(username); free(password);
270 0 : switch ( gc->gf ) {
271 : case gf_dir:
272 0 : _gio_file_dir(gc,path);
273 0 : break;
274 : case gf_statfile:
275 0 : _gio_file_statfile(gc,path);
276 0 : break;
277 : case gf_mkdir:
278 0 : _gio_file_mkdir(gc,path);
279 0 : break;
280 : case gf_delfile:
281 0 : _gio_file_delfile(gc,path);
282 0 : break;
283 : case gf_deldir:
284 0 : _gio_file_deldir(gc,path);
285 0 : break;
286 : case gf_renamefile:
287 0 : topath = _GIO_decomposeURL(gc->topath,&host,&port,&username,&password);
288 0 : free(host); free(username); free(password);
289 0 : _gio_file_renamefile(gc,path,topath);
290 0 : free(topath);
291 0 : break;
292 : default:
293 0 : break;
294 : }
295 0 : free(path);
296 0 : return( NULL );
297 : }
|