1 /*
2                                   NETWIB
3                              Network library
4                 Copyright(c) 1999-2010 Laurent Constantin
5                                   -----
6 
7   Main server   : http://www.laurentconstantin.com/
8   Backup server : http://laurentconstantin.free.fr/
9   [my current email address is on the web servers]
10 
11                                   -----
12   This file is part of Netwib.
13 
14   Netwib is free software: you can redistribute it and/or modify
15   it under the terms of the GNU General Public License version 3
16   as published by the Free Software Foundation.
17 
18   Netwib is distributed in the hope that it will be useful,
19   but WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21   GNU General Public License for more details (http://www.gnu.org/).
22 
23 ------------------------------------------------------------------------
24 */
25 
26 #include <netwib/inc/maininc.h>
27 
28 /*-------------------------------------------------------------*/
netwib_priv_path_info_smb(netwib_constdata data,netwib_uint32 datasize,netwib_buf * pbufbegin,netwib_bufext * pbufthen)29 static netwib_err netwib_priv_path_info_smb(netwib_constdata data,
30                                             netwib_uint32 datasize,
31                                             netwib_buf *pbufbegin,
32                                             netwib_bufext *pbufthen)
33 {
34   netwib_constdata dataori;
35   netwib_buf buf;
36 
37   /* data should contain "[\/][\/]server[\/]share[\/]*.*" */
38 
39   /* leading // or \\ was detected before calling this function. */
40   data += 2;
41   datasize -= 2;
42 
43   /* search the server */
44   dataori = data;
45   while (NETWIB_TRUE) {
46     if (datasize == 0) {
47       return(NETWIB_ERR_PAPATHNOTCANON);
48     }
49     if (*data == '/' || *data == '\\') {
50       break;
51     }
52     data++;
53     datasize--;
54   }
55   if (data - dataori == 0) {
56     return(NETWIB_ERR_PAPATHNOTCANON);
57   }
58   if (pbufbegin != NULL) {
59     netwib_er(netwib_buf_append_byte('/', pbufbegin));
60     netwib_er(netwib_buf_append_byte('/', pbufbegin));
61     netwib_er(netwib_buf_init_ext_arrayfilled(dataori, data - dataori, &buf));
62     netwib_er(netwib_buf_encode(&buf, NETWIB_ENCODETYPE_LOWERCASE, pbufbegin));
63     netwib_er(netwib_buf_append_byte('/', pbufbegin));
64   }
65   data++;
66   datasize--;
67 
68   /* now search the share */
69   dataori = data;
70   while (NETWIB_TRUE) {
71     if (datasize == 0 || *data == '/' || *data == '\\') {
72       break;
73     }
74     data++;
75     datasize--;
76   }
77   if (data - dataori == 0) {
78     /* path is invalid because there is no share name */
79     return(NETWIB_ERR_PAPATHNOTCANON);
80   }
81   if (pbufbegin != NULL) {
82     netwib_er(netwib_buf_init_ext_arrayfilled(dataori, data - dataori, &buf));
83     netwib_er(netwib_buf_encode(&buf, NETWIB_ENCODETYPE_LOWERCASE, pbufbegin));
84     netwib_er(netwib_buf_append_byte('/', pbufbegin));
85   }
86 
87   if (datasize == 0) {
88     netwib_er(netwib_buf_init_ext_string("/", pbufthen));/* MT safe */
89   } else {
90     netwib_er(netwib_buf_init_ext_arrayfilled(data, datasize, pbufthen));
91   }
92 
93   return(NETWIB_ERR_OK);
94 }
95 /* warning: output parameters are not consistent :
96      - pbufbegin : data is canonized and appended
97      - pbufthen : data is external pointing in ppathname (so not canonized)
98                   pbufthen is similar to core, but not canonized
99  */
netwib_priv_path_info(netwib_constbuf * ppathname,netwib_pathtype * ppathtype,netwib_buf * pbufbegin,netwib_bufext * pbufthen)100 static netwib_err netwib_priv_path_info(netwib_constbuf *ppathname,
101                                         netwib_pathtype *ppathtype,
102                                         netwib_buf *pbufbegin,
103                                         netwib_bufext *pbufthen)
104 {
105   netwib_data data;
106   netwib_uint32 datasize;
107   netwib_char c1, c2, c3;
108   netwib_err ret;
109 
110   datasize = netwib__buf_ref_data_size(ppathname);
111   if (datasize == 0) {
112     return(NETWIB_ERR_PAPATHNOTCANON);
113   }
114   data = netwib__buf_ref_data_ptr(ppathname);
115 
116   c1 = data[0];
117   c2 = (netwib_char)((datasize > 1)?data[1]:'\0');
118   c3 = (netwib_char)((datasize > 2)?data[2]:'\0');
119   if (ppathtype != NULL) {
120     *ppathtype = 0;
121   }
122   if (c1 == '.') {
123     if (ppathtype != NULL) {
124       *ppathtype = NETWIB_PATHTYPE_UNIX;
125     }
126     if (pbufbegin != NULL) {
127       netwib_er(netwib_buf_append_byte('.', pbufbegin));
128     }
129     if (pbufthen != NULL) {
130       netwib_er(netwib_buf_init_ext_arrayfilled(data, datasize, pbufthen));
131     }
132   } else if (c1 == '/' || c1 == '\\') {
133     netwib_bool issmb;
134     issmb = NETWIB_FALSE;
135     if (c2 == '/' || c2 == '\\') {
136       netwib_uint32 bufbeginsize;
137       netwib_buf bufthen;
138       bufbeginsize = netwib__buf_ref_data_sizenull(pbufbegin);
139       if (pbufthen == NULL) {
140         pbufthen = &bufthen;
141       }
142       ret = netwib_priv_path_info_smb(data, datasize, pbufbegin, pbufthen);
143       if (ret == NETWIB_ERR_OK) {
144         if (ppathtype != NULL) {
145           *ppathtype = NETWIB_PATHTYPE_WINSHARE | NETWIB_PATHTYPE_ABSOLUTE;
146           data = netwib__buf_ref_data_ptr(pbufthen);
147           datasize = netwib__buf_ref_data_size(pbufthen);
148           if (datasize == 1 && (data[0] == '/' || data[0] == '\\')) {
149             *ppathtype |= NETWIB_PATHTYPE_ROOT;
150           }
151         }
152         issmb = NETWIB_TRUE;
153       } else {
154         /* error, so suppose it's absolute (skip leading /) */
155         if (pbufbegin != NULL) {
156           pbufbegin->endoffset = pbufbegin->beginoffset + bufbeginsize;
157         }
158         data++;
159         datasize--;
160       }
161     }
162     if (!issmb) {
163       /* absolute path */
164       if (ppathtype != NULL) {
165         *ppathtype = NETWIB_PATHTYPE_UNIX | NETWIB_PATHTYPE_ABSOLUTE;
166         if (datasize == 1) *ppathtype |= NETWIB_PATHTYPE_ROOT;
167       }
168       if (pbufbegin != NULL) {
169         netwib_er(netwib_buf_append_byte('/', pbufbegin));
170       }
171       if (pbufthen != NULL) {
172         netwib_er(netwib_buf_init_ext_arrayfilled(data, datasize, pbufthen));
173       }
174     }
175   } else if (netwib_c2_isalpha(c1) && c2 == ':') {
176     if (ppathtype != NULL) {
177       *ppathtype = NETWIB_PATHTYPE_WINDRIVE;
178     }
179     if (pbufbegin != NULL) {
180       netwib_er(netwib_buf_append_byte((netwib_char)(netwib_c2_lc(c1)), pbufbegin));
181       netwib_er(netwib_buf_append_byte(':', pbufbegin));
182     }
183     if (c3 == '/' || c3 == '\\') {
184       if (ppathtype != NULL) {
185         *ppathtype |= NETWIB_PATHTYPE_ABSOLUTE;
186         if (datasize == 3) *ppathtype |= NETWIB_PATHTYPE_ROOT;
187       }
188       if (pbufbegin != NULL) {
189         netwib_er(netwib_buf_append_byte('/', pbufbegin));
190       }
191       if (pbufthen != NULL) {
192         netwib_er(netwib_buf_init_ext_arrayfilled(data+2, datasize-2,
193                                                   pbufthen));
194       }
195     } else if (c3 == '\0') {
196       if (pbufthen != NULL) {
197         netwib_er(netwib_buf_init_ext_string(".", pbufthen));/* MT safe */
198       }
199     } else {
200       if (pbufthen != NULL) {
201         netwib_er(netwib_buf_init_ext_arrayfilled(data+2, datasize-2,
202                                                   pbufthen));
203       }
204     }
205   } else {
206     /* suppose it's a relative path */
207     if (ppathtype != NULL) {
208       *ppathtype = NETWIB_PATHTYPE_UNIX;
209     }
210     if (pbufbegin != NULL) {
211       netwib_er(netwib_buf_append_byte('.', pbufbegin));
212     }
213     if (pbufthen != NULL) {
214       netwib_er(netwib_buf_init_ext_arrayfilled(data, datasize, pbufthen));
215     }
216   }
217 
218   return(NETWIB_ERR_OK);
219 }
220 
221 /*-------------------------------------------------------------*/
222 #define NETWIB_PRIV_PATH_CANON_LASTWAS_PATH 0
223 #define NETWIB_PRIV_PATH_CANON_LASTWAS_SLASH 1
224 #define NETWIB_PRIV_PATH_CANON_LASTWAS_DOT 2
netwib_priv_path_canon_goup(netwib_buf * pout,netwib_uint32 outinitsize,netwib_uint32 * plastwas)225 static netwib_err netwib_priv_path_canon_goup(netwib_buf *pout,
226                                               netwib_uint32 outinitsize,
227                                               netwib_uint32 *plastwas)
228 {
229   netwib_data data, pc;
230   netwib_uint32 datasize;
231 
232   /* convert :
233      /       to NETWIB_ERR_PAPATHROOTDOTDOT [/..]
234      .       to ..      [./..]
235      ..      to ../..   [../..]
236      x/..    to x/../.. [x/../..]
237      x/aa/bb to x/aa    [x/aa/bb/..]
238      x/aa    to x       [x/aa/..]
239      x       to .       [x/..]
240      /x      to /       [/x/..]
241   */
242 
243   data = netwib__buf_ref_data_ptr(pout) + outinitsize;
244   datasize = netwib__buf_ref_data_size(pout) - outinitsize;
245 
246   if (datasize == 1) {
247     if (data[0] == '/' || data[0] == '\\') {
248       return(NETWIB_ERR_PAPATHROOTDOTDOT);
249     }
250     if (data[0] == '.') {
251       /* "." to ".." */
252       netwib_er(netwib_buf_append_byte('.', pout));
253       *plastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_PATH;
254       return(NETWIB_ERR_OK);
255     }
256   }
257 
258   if (datasize == 2) {
259     if (data[0] == '.' && data[1] == '.') {
260       /* ".." to "../.." */
261       netwib_er(netwib_buf_append_string("/..", pout));
262       *plastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_PATH;
263       return(NETWIB_ERR_OK);
264     }
265   }
266 
267   if (datasize >= 3) {
268     pc = data + datasize - 3;
269     if (*pc == '/' || *pc == '\\') {
270       pc++;
271       if (*pc++ == '.') {
272         if (*pc == '.') {
273           /* "x/.." to "x/../.." */
274           netwib_er(netwib_buf_append_string("/..", pout));
275           *plastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_PATH;
276           return(NETWIB_ERR_OK);
277         }
278       }
279     }
280   }
281 
282   pc = data + datasize - 1;
283   while (NETWIB_TRUE) {
284     if (*pc == '/' || *pc == '\\') {
285       break;
286     }
287     pc--;
288     if (pc < data) {
289       /* no '/' found, so : "x" to "." */
290       pout->endoffset = pout->beginoffset + outinitsize;
291       netwib_er(netwib_buf_append_string(".", pout));
292       *plastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_DOT;
293       return(NETWIB_ERR_OK);
294     }
295   }
296   if (pc == data) {
297     /* "/x" to "/" */
298     pout->endoffset = pout->beginoffset + outinitsize + 1;
299     *plastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_SLASH;
300   } else {
301     /* "x/aa/bb" to "x/aa" */
302     pout->endoffset = pout->beginoffset + outinitsize + pc - data;
303     *plastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_PATH;
304   }
305 
306   return(NETWIB_ERR_OK);
307 }
308 /* works only on a NETWIB_PATHTYPE_UNIX path */
netwib_priv_path_canon(netwib_constbuf * ppathname,netwib_buf * pout)309 static netwib_err netwib_priv_path_canon(netwib_constbuf *ppathname,
310                                          netwib_buf *pout)
311 {
312   netwib_data data, dataori;
313   netwib_uint32 datasize, lastwas, outinitsize;
314 
315   datasize = netwib__buf_ref_data_size(ppathname);
316   if (datasize == 0) {
317     /* forbids empty filenames */
318     return(NETWIB_ERR_PAPATHNOTCANON);
319   }
320   data = netwib__buf_ref_data_ptr(ppathname);
321   outinitsize = netwib__buf_ref_data_size(pout);
322 
323   /* set root */
324   lastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_PATH;
325   if (data[0] == '/' || data[0] == '\\') {
326     netwib_er(netwib_buf_append_byte('/', pout));
327     lastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_SLASH;
328   } else {
329     netwib_er(netwib_buf_append_byte('.', pout));
330     lastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_DOT;
331   }
332 
333   /* main loop treating each directory */
334   while (NETWIB_TRUE) {
335     /* ensures data points to the begin of directory */
336     while (NETWIB_TRUE) {
337       if (datasize == 0) {
338         /* normal end */
339         return(NETWIB_ERR_OK);
340       }
341       if (*data != '/' && *data != '\\') {
342         break;
343       }
344       data++;
345       datasize--;
346     }
347     /* obtain the directory end */
348     dataori = data;
349     while (NETWIB_TRUE) {
350       if (datasize == 0 || *data == '/' || *data == '\\') {
351         break;
352       }
353       data++;
354       datasize--;
355     }
356     /* now, the directory name is between dataori and data */
357     if ((data-dataori == 1) && (dataori[0] == '.')) {
358       /* add nothing */
359     } else if ((data-dataori == 2) && (dataori[0] == '.')
360                && (dataori[1] == '.')) {
361       /* go up */
362       netwib_er(netwib_priv_path_canon_goup(pout, outinitsize, &lastwas));
363     } else {
364       /* add directory */
365       if (lastwas == NETWIB_PRIV_PATH_CANON_LASTWAS_DOT) {
366         pout->endoffset--; /* remove dot */
367       } else if (lastwas != NETWIB_PRIV_PATH_CANON_LASTWAS_SLASH) {
368         netwib_er(netwib_buf_append_byte('/', pout));
369       }
370       netwib_er(netwib_buf_append_data(dataori, data-dataori, pout));
371       lastwas = NETWIB_PRIV_PATH_CANON_LASTWAS_PATH;
372     }
373   }
374 
375   return(NETWIB_ERR_LOINTERNALERROR);
376 }
377 
378 /*-------------------------------------------------------------*/
379 /* pcanonizedpathname must contain "begin canonized" */
netwib_priv_path_append_then(netwib_pathtype beginpathtype,netwib_constbuf * pthen,netwib_buf * pcanonizedpathname)380 static netwib_err netwib_priv_path_append_then(netwib_pathtype beginpathtype,
381                                                netwib_constbuf *pthen,
382                                                netwib_buf *pcanonizedpathname)
383 {
384   netwib_data data;
385   netwib_uint32 size;
386 
387   if (beginpathtype & NETWIB_PATHTYPE_UNIX) {
388     pcanonizedpathname->endoffset--; /* suppress last / or . of begin */
389     netwib_er(netwib_priv_path_canon(pthen, pcanonizedpathname));
390   } else if (beginpathtype & NETWIB_PATHTYPE_WINDRIVE) {
391     if (beginpathtype & NETWIB_PATHTYPE_ABSOLUTE) {
392       pcanonizedpathname->endoffset--; /* suppress last / of begin */
393       netwib_er(netwib_priv_path_canon(pthen, pcanonizedpathname));
394     } else {
395       size = netwib__buf_ref_data_size(pcanonizedpathname);
396       netwib_er(netwib_priv_path_canon(pthen, pcanonizedpathname));
397       /* suppress last '.' in 'c:.' */
398       if (netwib__buf_ref_data_size(pcanonizedpathname) - size == 1) {
399         data = netwib__buf_ref_data_ptr(pcanonizedpathname);
400         if (data[size] == '.') {
401           pcanonizedpathname->endoffset--; /* suppress . of then */
402         }
403       }
404     }
405   } else if (beginpathtype & NETWIB_PATHTYPE_WINSHARE) {
406     pcanonizedpathname->endoffset--; /* suppress last / of begin */
407     netwib_er(netwib_priv_path_canon(pthen, pcanonizedpathname));
408   } else {
409     return(NETWIB_ERR_LOINTERNALERROR);
410   }
411 
412   return(NETWIB_ERR_OK);
413 }
414 
415 /*-------------------------------------------------------------*/
netwib_path_canon(netwib_constbuf * ppathname,netwib_buf * pcanonizedpathname)416 netwib_err netwib_path_canon(netwib_constbuf *ppathname,
417                              netwib_buf *pcanonizedpathname)
418 {
419   netwib_buf then;
420   netwib_pathtype pathtype;
421 
422   /* directly store begin in pcanonizedpathname */
423   netwib_er(netwib_priv_path_info(ppathname, &pathtype, pcanonizedpathname,
424                                   &then));
425 
426   /* append then */
427   netwib_er(netwib_priv_path_append_then(pathtype, &then,
428                                          pcanonizedpathname));
429 
430   return(NETWIB_ERR_OK);
431 }
432 
433 /*-------------------------------------------------------------*/
netwib_pathtype_init(netwib_constbuf * ppathname,netwib_pathtype * ppathtype)434 netwib_err netwib_pathtype_init(netwib_constbuf *ppathname,
435                                 netwib_pathtype *ppathtype)
436 {
437   netwib_er(netwib_priv_path_info(ppathname, ppathtype, NULL, NULL));
438   return(NETWIB_ERR_OK);
439 }
440 
441 /*-------------------------------------------------------------*/
netwib_path_decode(netwib_constbuf * ppathname,netwib_path_decodetype type,netwib_buf * pout)442 netwib_err netwib_path_decode(netwib_constbuf *ppathname,
443                               netwib_path_decodetype type,
444                               netwib_buf *pout)
445 {
446   netwib_pathtype pathtype;
447   netwib_byte buftmparray[512];
448   netwib_buf buftmp, then;
449   netwib_data data;
450   netwib_uint32 datasize;
451   netwib_err ret;
452 
453   if (netwib__buf_ref_data_sizenull(ppathname) == 0) {
454     return(NETWIB_ERR_PAPATHNOTCANON);
455   }
456 
457   switch(type) {
458   case NETWIB_PATH_DECODETYPE_BEGIN :
459     netwib_er(netwib_priv_path_info(ppathname, NULL, pout, NULL));
460     break;
461   case NETWIB_PATH_DECODETYPE_CORE :
462     netwib_er(netwib_priv_path_info(ppathname, NULL, NULL, &then));
463     netwib_er(netwib_priv_path_canon(&then, pout));
464     break;
465   case NETWIB_PATH_DECODETYPE_PARENT :
466     /* We could simply convert "a/b" to "a", but there are cases such
467        as "a/.." to "a/../.." which are not so easy. So, use buftmp. */
468     netwib_er(netwib_priv_path_info(ppathname, &pathtype, pout, &then));
469     netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmparray, &buftmp));
470     netwib_er(netwib_buf_append_buf(&then, &buftmp));
471     netwib_er(netwib_buf_append_string("/..", &buftmp));
472     ret = netwib_priv_path_append_then(pathtype, &buftmp, pout);
473     netwib_er(netwib_buf_close(&buftmp));
474     netwib_er(ret);
475     break;
476   case NETWIB_PATH_DECODETYPE_CHILD :
477     /* We could use last part, but there are cases such as "a/" or "a/."
478        which are not so easy. So, use buftmp, and canonize it. */
479     netwib_er(netwib_priv_path_info(ppathname, NULL, NULL, &then));
480     netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmparray, &buftmp));
481     ret = netwib_priv_path_canon(&then, &buftmp);
482     if (ret == NETWIB_ERR_OK) {
483       datasize = netwib__buf_ref_data_size(&buftmp);
484       if (datasize == 0) {
485         return(NETWIB_ERR_LOINTERNALERROR);
486       }
487       data = netwib__buf_ref_data_ptr(&buftmp);
488       if (datasize == 1 && data[0] == '/') {
489         netwib_er(netwib_buf_append_byte('/', pout));
490       } else {
491         data += datasize;
492         while (datasize--) {
493           data--;
494           if (*data == '/') {
495             data++;
496             break;
497           }
498         }
499         netwib_er(netwib_buf_append_data(data, netwib__buf_ref_data_size(&buftmp) - datasize - 1, pout));
500       }
501     }
502     netwib_er(netwib_buf_close(&buftmp));
503     netwib_er(ret);
504     break;
505   case NETWIB_PATH_DECODETYPE_EXTENSION :
506     datasize = netwib__buf_ref_data_size(ppathname);
507     data = netwib__buf_ref_data_ptr(ppathname);
508     data += datasize;
509     while (NETWIB_TRUE) {
510       if (datasize == 0) { /* no extension */
511         netwib_er(netwib_buf_init_ext_empty(pout));
512         return(NETWIB_ERR_OK);
513       }
514       datasize--;
515       data--;
516       if (*data == '.') {
517         data++;
518         break;
519       }
520       if (*data == '/' || *data == '\\') { /* no extension */
521         netwib_er(netwib_buf_init_ext_empty(pout));
522         return(NETWIB_ERR_OK);
523       }
524     }
525     netwib_er(netwib_buf_init_ext_arrayfilled(data, netwib__buf_ref_data_size(ppathname) - datasize - 1, pout));
526     break;
527   default :
528     return(NETWIB_ERR_PAINVALIDTYPE);
529     break;
530   }
531 
532   return(NETWIB_ERR_OK);
533 }
534 
535 /*-------------------------------------------------------------*/
netwib_priv_path_begin_cmp(netwib_constbuf * pbegin1,netwib_pathtype pathtype1,netwib_constbuf * pbegin2,netwib_pathtype pathtype2,netwib_bool ignoreroot)536 static netwib_err netwib_priv_path_begin_cmp(netwib_constbuf *pbegin1,
537                                              netwib_pathtype pathtype1,
538                                              netwib_constbuf *pbegin2,
539                                              netwib_pathtype pathtype2,
540                                              netwib_bool ignoreroot)
541 {
542   netwib_buf begin1, begin2;
543   netwib_cmp cmp;
544 
545   if (pathtype1 & NETWIB_PATHTYPE_UNIX) {
546     if (!(pathtype2 & NETWIB_PATHTYPE_UNIX)) {
547       return(NETWIB_ERR_PAPATHCANTINIT);
548     }
549     if (!ignoreroot) {
550       netwib_er(netwib_buf_cmp(pbegin1, pbegin2, &cmp));
551       if (cmp != NETWIB_CMP_EQ) {
552         return(NETWIB_ERR_PAPATHCANTINIT);
553       }
554     }
555   } else if (pathtype1 & NETWIB_PATHTYPE_WINSHARE) {
556     if (!(pathtype2 & NETWIB_PATHTYPE_WINSHARE)) {
557       return(NETWIB_ERR_PAPATHCANTINIT);
558     }
559     netwib_er(netwib_buf_cmp(pbegin1, pbegin2, &cmp));
560     if (cmp != NETWIB_CMP_EQ) {
561       return(NETWIB_ERR_PAPATHCANTINIT);
562     }
563   } else if (pathtype1 & NETWIB_PATHTYPE_WINDRIVE) {
564     if (!(pathtype2 & NETWIB_PATHTYPE_WINDRIVE)) {
565       return(NETWIB_ERR_PAPATHCANTINIT);
566     }
567     begin1 = *pbegin1;
568     begin2 = *pbegin2;
569     if (ignoreroot) {
570       if (pathtype1 & NETWIB_PATHTYPE_ABSOLUTE) {
571         begin1.endoffset--; /* ignore "c:'/'" for comparing */
572       }
573       if (pathtype2 & NETWIB_PATHTYPE_ABSOLUTE) {
574         begin2.endoffset--; /* ignore "c:'/'" for comparing */
575       }
576     }
577     netwib_er(netwib_buf_cmp(&begin1, &begin2, &cmp));
578     if (cmp != NETWIB_CMP_EQ) {
579       return(NETWIB_ERR_PAPATHCANTINIT);
580     }
581   } else {
582     return(NETWIB_ERR_LOINTERNALERROR);
583   }
584 
585   return(NETWIB_ERR_OK);
586 }
587 
588 /*-------------------------------------------------------------*/
netwib_priv_path_init_concat(netwib_constbuf * pdirname1,netwib_constbuf * ppathname2,netwib_buf * pout)589 static netwib_err netwib_priv_path_init_concat(netwib_constbuf *pdirname1,
590                                                netwib_constbuf *ppathname2,
591                                                netwib_buf *pout)
592 {
593   netwib_byte buftmp1array[512], buftmp2array[512];
594   netwib_buf buftmp1, buftmp2, then1, then2;
595   netwib_pathtype pathtype1, pathtype2;
596   netwib_err ret=NETWIB_ERR_OK;
597 
598   /* initialize buffers */
599   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp1array, &buftmp1));
600   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp2array, &buftmp2));
601 
602   /* obtain information */
603   netwib_eg(netwib_priv_path_info(pdirname1, &pathtype1, &buftmp1, &then1));
604   netwib_eg(netwib_priv_path_info(ppathname2, &pathtype2, &buftmp2, &then2));
605 
606   /* check parameters */
607   if (pathtype2 & NETWIB_PATHTYPE_ABSOLUTE) {
608     if (!(pathtype1 & NETWIB_PATHTYPE_ROOT)) {
609       /* if ppathname2 is absolute, pdirname1 must be a root */
610       netwib_eg(NETWIB_ERR_PAPATHCANTINIT);
611     }
612     /* if ppathname2 is absolute, pdirname1 must be the same root */
613     if (!(pathtype2 & NETWIB_PATHTYPE_UNIX)) {
614       netwib_eg(netwib_priv_path_begin_cmp(&buftmp1, pathtype1, &buftmp2,
615                                            pathtype2, NETWIB_FALSE));
616     }
617   } else {
618     /* the root must be the same */
619     if (!(pathtype2 & NETWIB_PATHTYPE_UNIX)) {
620       netwib_eg(netwib_priv_path_begin_cmp(&buftmp1, pathtype1, &buftmp2,
621                                            pathtype2, NETWIB_TRUE));
622     }
623   }
624 
625   /* create path */
626   netwib__buf_reinit(&buftmp2);
627   netwib_eg(netwib_buf_append_buf(&then1, &buftmp2));
628   netwib_eg(netwib_buf_append_byte('/', &buftmp2));
629   netwib_eg(netwib_buf_append_buf(&then2, &buftmp2));
630   netwib_eg(netwib_priv_path_append_then(pathtype1, &buftmp2, &buftmp1));
631   netwib_eg(netwib_buf_append_buf(&buftmp1, pout));
632 
633   /* close */
634  netwib_gotolabel:
635   netwib_er(netwib_buf_close(&buftmp2));
636   netwib_er(netwib_buf_close(&buftmp1));
637   return(ret);
638 }
639 
640 /*-------------------------------------------------------------*/
netwib_priv_path_init_jail(netwib_constbuf * pdirname1,netwib_constbuf * ppathname2,netwib_buf * pout)641 static netwib_err netwib_priv_path_init_jail(netwib_constbuf *pdirname1,
642                                              netwib_constbuf *ppathname2,
643                                              netwib_buf *pout)
644 {
645   netwib_byte buftmp2array[512], buftmp3array[512];
646   netwib_buf buftmp2, buftmp3, then1, then2;
647   netwib_pathtype pathtype1, pathtype2;
648   netwib_err ret=NETWIB_ERR_OK;
649 
650   /* initialize buffers */
651   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp2array, &buftmp2));
652   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp3array, &buftmp3));
653 
654   /* obtain information */
655   netwib_eg(netwib_priv_path_info(pdirname1, &pathtype1, pout, &then1));
656   netwib_eg(netwib_priv_path_info(ppathname2, &pathtype2, NULL, &then2));
657 
658   /* check parameters */
659   if (pathtype2 & NETWIB_PATHTYPE_WINDRIVE) {
660     /* for security reasons, this should not be allowed */
661     netwib_goto(NETWIB_ERR_PAPATHCANTINIT);
662   }
663   if (pathtype2 & NETWIB_PATHTYPE_WINSHARE) {
664     /* for security reasons, this should not be allowed */
665     netwib_goto(NETWIB_ERR_PAPATHCANTINIT);
666   }
667 
668   /* create path */
669   netwib_eg(netwib_buf_append_buf(&then1, &buftmp2));
670   netwib_eg(netwib_buf_append_byte('/', &buftmp3));
671   netwib_eg(netwib_buf_append_buf(&then2, &buftmp3));
672   netwib_eg(netwib_priv_path_canon(&buftmp3, &buftmp2));
673   netwib_eg(netwib_priv_path_append_then(pathtype1, &buftmp2, pout));
674 
675   /* close */
676  netwib_gotolabel:
677   netwib_er(netwib_buf_close(&buftmp3));
678   netwib_er(netwib_buf_close(&buftmp2));
679   return(ret);
680 }
681 
682 /*-------------------------------------------------------------*/
netwib_priv_path_init_abs(netwib_constbuf * pdirname1,netwib_constbuf * ppathname2,netwib_buf * pout)683 static netwib_err netwib_priv_path_init_abs(netwib_constbuf *pdirname1,
684                                             netwib_constbuf *ppathname2,
685                                             netwib_buf *pout)
686 {
687   netwib_byte buftmp1array[512], buftmp2array[512];
688   netwib_buf buftmp1, buftmp2, then1, then2;
689   netwib_pathtype pathtype1, pathtype2;
690   netwib_err ret=NETWIB_ERR_OK;
691 
692   /* initialize buffers */
693   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp1array, &buftmp1));
694   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp2array, &buftmp2));
695 
696   /* check parameters */
697   netwib_eg(netwib_priv_path_info(ppathname2, &pathtype2, &buftmp2, &then2));
698   if (pathtype2 & NETWIB_PATHTYPE_ABSOLUTE) {
699     netwib_eg(netwib_buf_append_buf(ppathname2, pout));
700     netwib_goto(NETWIB_ERR_OK);
701   }
702   netwib_eg(netwib_priv_path_info(pdirname1, &pathtype1, &buftmp1, &then1));
703   if (!(pathtype1 & NETWIB_PATHTYPE_ABSOLUTE)) {
704     netwib_eg(NETWIB_ERR_PAPATHCANTINIT);
705   }
706 
707   /* check parameters */
708   if (!(pathtype2 & NETWIB_PATHTYPE_UNIX)) {
709     netwib_eg(netwib_priv_path_begin_cmp(&buftmp1, pathtype1, &buftmp2,
710                                          pathtype2, NETWIB_TRUE));
711   }
712 
713   /* create path */
714   netwib__buf_reinit(&buftmp2);
715   netwib_eg(netwib_buf_append_buf(&then1, &buftmp2));
716   netwib_eg(netwib_buf_append_byte('/', &buftmp2));
717   netwib_eg(netwib_buf_append_buf(&then2, &buftmp2));
718   netwib_eg(netwib_priv_path_append_then(pathtype1, &buftmp2, &buftmp1));
719   netwib_eg(netwib_buf_append_buf(&buftmp1, pout));
720 
721   /* close */
722  netwib_gotolabel:
723   netwib_er(netwib_buf_close(&buftmp2));
724   netwib_er(netwib_buf_close(&buftmp1));
725   return(ret);
726 }
727 
728 /*-------------------------------------------------------------*/
netwib_priv_path_init_rel(netwib_constbuf * ppathname1,netwib_constbuf * ppathname2,netwib_buf * pout)729 static netwib_err netwib_priv_path_init_rel(netwib_constbuf *ppathname1,
730                                             netwib_constbuf *ppathname2,
731                                             netwib_buf *pout)
732 {
733   netwib_byte buftmp1array[512], buftmp2array[512], buftmp3array[512];
734   netwib_buf buftmp1, buftmp2, buftmp3;
735   netwib_string pc1, pc2, pitem1, pitem2;
736   netwib_err ret=NETWIB_ERR_OK;
737 
738   /* initialize buffers */
739   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp1array, &buftmp1));
740   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp2array, &buftmp2));
741   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp3array, &buftmp3));
742 
743   /* first, canonize */
744   netwib_eg(netwib_priv_path_canon(ppathname1, &buftmp1));
745   netwib_eg(netwib_priv_path_canon(ppathname2, &buftmp2));
746   netwib_eg(netwib_buf_ref_string(&buftmp1, &pc1));
747   netwib_eg(netwib_buf_ref_string(&buftmp2, &pc2));
748 
749   /* find the common part */
750   pitem1 = pc1;
751   pitem2 = pc2;
752   while (NETWIB_TRUE) {
753     if (*pc1 != *pc2) {
754       if (*pc1 == '\0' && *pc2 == '/') {
755         pitem1 = NULL; /* means end */
756         pitem2 = pc2+1; /* char after '/'*/
757       }
758       if (*pc1 == '/' && *pc2 == '\0') {
759         pitem1 = pc1+1; /* char after '/'*/
760         pitem2 = NULL; /* means end */
761       }
762       break;
763     }
764     if (*pc1 == '\0' /* comparing pc2 is not needed because *pc1 == *pc2 */) {
765       pitem1 = NULL; /* means end */
766       pitem2 = NULL; /* means end */
767       break;
768     }
769     if (*pc1 == '/' /* comparing pc2 is not needed because *pc1 == *pc2 */) {
770       pitem1 = pc1+1; /* char after '/'*/
771       pitem2 = pc2+1; /* char after '/'*/
772     }
773     pc1++;
774     pc2++;
775   }
776   /* now, cases "pci+1" (to go char after '/') have to be converted to NULL */
777   if (pitem1 != NULL && *pitem1 == '\0') pitem1 = NULL;
778   if (pitem2 != NULL && *pitem2 == '\0') pitem2 = NULL;
779 
780   if (pitem1 != NULL) {
781     /* if pitem1 points to "../xyz", we cannot determine */
782     if (pitem1[0] == '.' && pitem1[1] == '.' && pitem1[2] == '/') {
783       netwib_eg(NETWIB_ERR_PAPATHCANTINIT);
784     }
785     /* loop till the end of pc1 to create "../../../" */
786     pc1 = pitem1;
787     while (*pc1 != '\0') {
788       if (*pc1 == '/') {
789         netwib_eg(netwib_buf_append_string("../", pout));
790       }
791       pc1++;
792     }
793     netwib_eg(netwib_buf_append_string("..", pout));
794     if (pitem2 != NULL) {
795       netwib_eg(netwib_buf_append_string("/", pout));
796       /* pitem2 is already canonized, so use it */
797       netwib_eg(netwib_buf_append_string(pitem2, pout));
798     }
799   } else {
800     /* if pitem1 is NULL, there is no "../../../" to create */
801     if (pitem2 != NULL) {
802       /* pitem2 is already canonized, so use it */
803       netwib_eg(netwib_buf_append_string(pitem2, pout));
804     } else {
805       netwib_eg(netwib_buf_append_string(".", pout));
806     }
807   }
808 
809   /* close */
810  netwib_gotolabel:
811   netwib_er(netwib_buf_close(&buftmp3));
812   netwib_er(netwib_buf_close(&buftmp2));
813   netwib_er(netwib_buf_close(&buftmp1));
814   return(ret);
815 }
816 
817 /*-------------------------------------------------------------*/
netwib_priv_path_init_rela(netwib_constbuf * pdirname1,netwib_constbuf * ppathname2,netwib_buf * pout)818 static netwib_err netwib_priv_path_init_rela(netwib_constbuf *pdirname1,
819                                              netwib_constbuf *ppathname2,
820                                              netwib_buf *pout)
821 {
822   netwib_byte buftmp1array[512], buftmp2array[512];
823   netwib_buf buftmp1, buftmp2, then1, then2;
824   netwib_pathtype pathtype1, pathtype2;
825   netwib_err ret=NETWIB_ERR_OK;
826 
827   /* initialize buffers */
828   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp1array, &buftmp1));
829   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp2array, &buftmp2));
830 
831   /* obtain information */
832   netwib_eg(netwib_priv_path_info(pdirname1, &pathtype1, &buftmp1, &then1));
833   netwib_eg(netwib_priv_path_info(ppathname2, &pathtype2, &buftmp2, &then2));
834 
835   /* check parameters */
836   if (pathtype2 & NETWIB_PATHTYPE_ABSOLUTE) {
837     if (!(pathtype1 & NETWIB_PATHTYPE_ABSOLUTE)) {
838       netwib_eg(NETWIB_ERR_PAPATHCANTINIT);
839     }
840     if (!(pathtype2 & NETWIB_PATHTYPE_UNIX)) {
841       netwib_eg(netwib_priv_path_begin_cmp(&buftmp1, pathtype1, &buftmp2,
842                                            pathtype2, NETWIB_TRUE));
843     }
844     netwib_eg(netwib_priv_path_init_rel(&then1, &then2, pout));
845   } else {
846     /* ensure root is the same */
847     if (!(pathtype2 & NETWIB_PATHTYPE_UNIX)) {
848       netwib_eg(netwib_priv_path_begin_cmp(&buftmp1, pathtype1, &buftmp2,
849                                            pathtype2, NETWIB_TRUE));
850     }
851     /* if ppathname2 is relative, use it */
852     netwib_eg(netwib_priv_path_canon(ppathname2, pout));
853   }
854 
855   /* close */
856  netwib_gotolabel:
857   netwib_er(netwib_buf_close(&buftmp2));
858   netwib_er(netwib_buf_close(&buftmp1));
859   return(ret);
860 }
861 
862 /*-------------------------------------------------------------*/
netwib_priv_path_init_relb(netwib_constbuf * pdirname1,netwib_constbuf * ppathname2,netwib_buf * pout)863 static netwib_err netwib_priv_path_init_relb(netwib_constbuf *pdirname1,
864                                              netwib_constbuf *ppathname2,
865                                              netwib_buf *pout)
866 {
867   netwib_byte buftmp1array[512], buftmp2array[512];
868   netwib_buf buftmp1, buftmp2, then1, then2;
869   netwib_pathtype pathtype1, pathtype2;
870   netwib_err ret=NETWIB_ERR_OK;
871 
872   /* initialize buffers */
873   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp1array, &buftmp1));
874   netwib_er(netwib_buf_init_ext_storagearraysizeof(buftmp2array, &buftmp2));
875 
876   /* obtain information */
877   netwib_eg(netwib_priv_path_info(pdirname1, &pathtype1, &buftmp1, &then1));
878   netwib_eg(netwib_priv_path_info(ppathname2, &pathtype2, &buftmp2, &then2));
879 
880   /* check parameters */
881   netwib_eg(netwib_priv_path_begin_cmp(&buftmp1, pathtype1, &buftmp2,
882                                        pathtype2, NETWIB_FALSE));
883 
884   /* create path */
885   netwib_eg(netwib_priv_path_init_rel(&then1, &then2, pout));
886 
887   /* close */
888  netwib_gotolabel:
889   netwib_er(netwib_buf_close(&buftmp2));
890   netwib_er(netwib_buf_close(&buftmp1));
891   return(ret);
892 }
893 
894 /*-------------------------------------------------------------*/
netwib_path_init(netwib_constbuf * pdirname1,netwib_constbuf * ppathname2,netwib_path_inittype type,netwib_buf * pout)895 netwib_err netwib_path_init(netwib_constbuf *pdirname1,
896                             netwib_constbuf *ppathname2,
897                             netwib_path_inittype type,
898                             netwib_buf *pout)
899 {
900   netwib_err ret=NETWIB_ERR_OK;
901 
902   if (netwib__buf_ref_data_sizenull(pdirname1) == 0 ||
903       netwib__buf_ref_data_sizenull(ppathname2) == 0) {
904     return(NETWIB_ERR_PAPATHNOTCANON);
905   }
906 
907   switch(type) {
908     case NETWIB_PATH_INITTYPE_CONCAT :
909       ret = netwib_priv_path_init_concat(pdirname1, ppathname2, pout);
910       break;
911     case NETWIB_PATH_INITTYPE_JAIL :
912       ret = netwib_priv_path_init_jail(pdirname1, ppathname2, pout);
913       break;
914     case NETWIB_PATH_INITTYPE_ABS :
915       ret = netwib_priv_path_init_abs(pdirname1, ppathname2, pout);
916       break;
917     case NETWIB_PATH_INITTYPE_RELA :
918       ret = netwib_priv_path_init_rela(pdirname1, ppathname2, pout);
919       break;
920     case NETWIB_PATH_INITTYPE_RELB :
921       ret = netwib_priv_path_init_relb(pdirname1, ppathname2, pout);
922       break;
923   }
924 
925   if (ret == NETWIB_ERR_PAPATHROOTDOTDOT || ret == NETWIB_ERR_PAPATHNOTCANON) {
926     ret = NETWIB_ERR_PAPATHCANTINIT;
927   }
928 
929   return(ret);
930 }
931