]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/filedir.c
DROPKLUDGE fix to "move" procedure and a few general code cleanup things
[netatalk.git] / etc / afpd / filedir.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <errno.h>
11 #include <sys/syslog.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/param.h>
15 #include <netatalk/endian.h>
16 #include <atalk/adouble.h>
17 #include <atalk/afp.h>
18 #include <atalk/util.h>
19 #include <atalk/cnid.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fcntl.h>
23 #include <dirent.h>
24 #include <string.h>
25 #ifdef DROPKLUDGE
26 #include <unistd.h>
27 #endif DROPKLUDGE
28
29 #include "directory.h"
30 #include "desktop.h"
31 #include "volume.h"
32 #include "fork.h"
33 #include "file.h"
34 #include "globals.h"
35 #include "filedir.h"
36
37 int afp_getfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
38     AFPObj      *obj;
39     char        *ibuf, *rbuf;
40     int         ibuflen, *rbuflen;
41 {
42     struct stat         st;
43     struct vol          *vol;
44     struct dir          *dir;
45     u_int32_t           did;
46     int                 buflen, ret;
47     char                *path;
48     u_int16_t           fbitmap, dbitmap, vid;
49
50     *rbuflen = 0;
51     ibuf += 2;
52
53     memcpy( &vid, ibuf, sizeof( vid ));
54     ibuf += sizeof( vid );
55     if (( vol = getvolbyvid( vid )) == NULL ) {
56         return( AFPERR_PARAM );
57     }
58
59     memcpy( &did, ibuf, sizeof( did ));
60     ibuf += sizeof( did );
61
62     if (( dir = dirsearch( vol, did )) == NULL ) {
63         return( AFPERR_NOOBJ );
64     }
65
66     memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
67     fbitmap = ntohs( fbitmap );
68     ibuf += sizeof( fbitmap );
69     memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
70     dbitmap = ntohs( dbitmap );
71     ibuf += sizeof( dbitmap );
72
73     if (( path = cname( vol, dir, &ibuf )) == NULL) {
74         return( AFPERR_NOOBJ );
75     }
76
77     if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
78         return( AFPERR_NOOBJ );
79     }
80
81     buflen = 0;
82     if (S_ISDIR(st.st_mode)) {
83         if (dbitmap && ( ret = getdirparams(vol, dbitmap, ".", curdir,
84                 &st, rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
85             return( ret );
86         }
87         /* this is a directory */
88         *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISDIR; 
89     } else {
90         if (fbitmap && ( ret = getfilparams(vol, fbitmap, path, curdir, &st,
91                 rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
92             return( ret );
93         }
94         /* this is a file */
95         *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISFILE;
96     }
97     *rbuflen = buflen + 3 * sizeof( u_int16_t );
98     fbitmap = htons( fbitmap );
99     memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
100     rbuf += sizeof( fbitmap );
101     dbitmap = htons( dbitmap );
102     memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
103     rbuf += sizeof( dbitmap ) + sizeof( u_char );
104     *rbuf = 0;
105
106     return( AFP_OK );
107 }
108
109 int afp_setfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
110     AFPObj      *obj;
111     char        *ibuf, *rbuf;
112     int         ibuflen, *rbuflen;
113 {
114     struct stat st;
115     struct vol  *vol;
116     struct dir  *dir;
117     char        *path;
118     u_int16_t   vid, bitmap;
119     int         did, rc;
120
121     *rbuflen = 0;
122     ibuf += 2;
123     memcpy( &vid, ibuf, sizeof(vid));
124     ibuf += sizeof( vid );
125
126     if (( vol = getvolbyvid( vid )) == NULL ) {
127         return( AFPERR_PARAM );
128     }
129
130     if (vol->v_flags & AFPVOL_RO)
131         return AFPERR_VLOCK;
132
133     memcpy( &did, ibuf, sizeof( did));
134     ibuf += sizeof( did);
135
136     if (( dir = dirsearch( vol, did )) == NULL ) {
137         return( AFPERR_NOOBJ );
138     }
139
140     memcpy( &bitmap, ibuf, sizeof( bitmap ));
141     bitmap = ntohs( bitmap );
142     ibuf += sizeof( bitmap );
143
144     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
145         return( AFPERR_NOOBJ );
146     }
147
148     if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
149         return( AFPERR_NOOBJ );
150     }
151
152     /*
153      * If ibuf is odd, make it even.
154      */
155     if ((u_long)ibuf & 1 ) {
156         ibuf++;
157     }
158
159     if (S_ISDIR(st.st_mode)) {
160         rc = setdirparams(vol, path, bitmap, ibuf );
161     } else {
162         rc = setfilparams(vol, path, bitmap, ibuf );
163     }
164     if ( rc == AFP_OK ) {
165         setvoltime(obj, vol );
166     }
167     return( rc );
168 }
169
170 int afp_rename(obj, ibuf, ibuflen, rbuf, rbuflen )
171     AFPObj      *obj;
172     char        *ibuf, *rbuf;
173     int         ibuflen, *rbuflen;
174 {
175     struct adouble      ad;
176     struct stat         st;
177     struct vol          *vol;
178     struct dir          *dir, *odir = NULL;
179     char                *path, *buf, *upath, *newpath;
180     char                *newadpath;
181     u_int32_t           did;
182     int                 plen;
183     u_int16_t           vid;
184 #if AD_VERSION > AD_VERSION1
185     cnid_t              id;
186 #endif
187
188     *rbuflen = 0;
189     ibuf += 2;
190
191     memcpy( &vid, ibuf, sizeof( vid ));
192     ibuf += sizeof( vid );
193     if (( vol = getvolbyvid( vid )) == NULL ) {
194         return( AFPERR_PARAM );
195     }
196
197     if (vol->v_flags & AFPVOL_RO)
198         return AFPERR_VLOCK;
199
200     memcpy( &did, ibuf, sizeof( did ));
201     ibuf += sizeof( did );
202     if (( dir = dirsearch( vol, did )) == NULL ) {
203         return( AFPERR_NOOBJ );
204     }
205
206     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
207         return( AFPERR_NOOBJ );
208     }
209
210     /* another place where we know about the path type */
211     if ( *ibuf++ != 2 ) {
212         return( AFPERR_PARAM );
213     }
214     plen = (unsigned char) *ibuf++;
215     *( ibuf + plen ) = '\0';
216
217     if ( *path == '\0' ) {
218         if ( curdir->d_parent == NULL ) { /* root directory */
219             return( AFPERR_NORENAME );
220         }
221         odir = curdir;
222         path = curdir->d_name;
223         if ( movecwd( vol, curdir->d_parent ) < 0 ) {
224             return( AFPERR_NOOBJ );
225         }
226     }
227
228 #ifdef notdef
229     if ( strcasecmp( path, ibuf ) == 0 ) {
230         return( AFP_OK );
231     }
232 #endif notdef
233
234     /* if a curdir/newname ofork exists, return busy */
235     if (of_findname(vol, curdir, ibuf))
236         return AFPERR_BUSY;
237
238     /* source == destination. just say okay. */
239     if (strcmp(path, ibuf) == 0)
240         return AFP_OK;
241
242     /* check for illegal characters */
243     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
244         strpbrk(ibuf, MSWINDOWS_BADCHARS))
245         return AFPERR_PARAM;
246
247     newpath = obj->oldtmp;
248     strcpy( newpath, mtoupath(vol, ibuf ));
249
250     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(newpath, '/'))
251       return AFPERR_PARAM;
252
253     if (!validupath(vol, newpath))
254       return AFPERR_EXIST;
255
256     /* the strdiacasecmp deals with case-insensitive, case preserving
257        filesystems */
258     if (stat( newpath, &st ) == 0 && strdiacasecmp(path, ibuf))
259         return( AFPERR_EXIST );
260
261     upath = mtoupath(vol, path);
262
263 #if AD_VERSION > AD_VERSION1
264     id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
265 #endif
266
267     if ( rename( upath, newpath ) < 0 ) {
268         switch ( errno ) {
269         case ENOENT :
270             return( AFPERR_NOOBJ );
271         case EACCES :
272             return( AFPERR_ACCESS );
273         default :
274             return( AFPERR_PARAM );
275         }
276     }
277
278 #if AD_VERSION > AD_VERSION1
279     if (stat(newpath, &st) < 0) /* this shouldn't fail */
280       return AFPERR_MISC;
281     cnid_update(vol->v_db, id, &st, curdir->d_did, newpath, strlen(newpath));
282 #endif
283
284     if ( !odir ) {
285         newadpath = obj->newtmp;
286         strcpy( newadpath, ad_path( newpath, 0 ));
287         if ( rename( ad_path( upath, 0 ), newadpath ) < 0 ) {
288             if ( errno == ENOENT ) {    /* no adouble header file */
289                 if (( unlink( newadpath ) < 0 ) && ( errno != ENOENT )) {
290                     return( AFPERR_PARAM );
291                 }
292                 goto out;
293             }
294             return( AFPERR_PARAM );
295         }
296
297         memset(&ad, 0, sizeof(ad));
298         if ( ad_open( newpath, ADFLAGS_HF, O_RDWR|O_CREAT, 0666,
299                       &ad) < 0 ) {
300             return( AFPERR_PARAM );
301         }
302     } else {
303         int isad = 1;
304
305         memset(&ad, 0, sizeof(ad));
306         if ( ad_open( newpath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR, 
307                       O_RDWR|O_CREAT, 0666, &ad) < 0 ) {
308             if (!((errno == ENOENT) && vol_noadouble(vol)))
309               return( AFPERR_PARAM );
310             isad = 0;
311         }
312         if ((buf = realloc( odir->d_name, plen + 1 )) == NULL ) {
313             syslog( LOG_ERR, "afp_rename: realloc: %m" );
314             if (isad) {
315               ad_flush(&ad, ADFLAGS_HF); /* in case of create */
316               ad_close(&ad, ADFLAGS_HF);
317             }
318             return AFPERR_MISC;
319         }
320         odir->d_name = buf;
321         strcpy( odir->d_name, ibuf );
322         if (!isad)
323           goto out;
324     }
325
326     ad_setentrylen( &ad, ADEID_NAME, plen );
327     memcpy( ad_entry( &ad, ADEID_NAME ), ibuf, plen );
328     ad_flush( &ad, ADFLAGS_HF );
329     ad_close( &ad, ADFLAGS_HF );
330
331 out:
332     setvoltime(obj, vol );
333
334     /* if it's still open, rename the ofork as well. */
335     if (of_rename(vol, curdir, path, curdir, ibuf) < 0)
336         return AFPERR_MISC;
337
338     return( AFP_OK );
339 }
340
341
342 int afp_delete(obj, ibuf, ibuflen, rbuf, rbuflen )
343     AFPObj      *obj;
344     char        *ibuf, *rbuf;
345     int         ibuflen, *rbuflen;
346 {
347     struct vol          *vol;
348     struct dir          *dir;
349     char                *path, *upath;
350     int                 did, rc;
351     u_int16_t           vid;
352
353     *rbuflen = 0;
354     ibuf += 2;
355
356     memcpy( &vid, ibuf, sizeof( vid ));
357     ibuf += sizeof( vid );
358     if (( vol = getvolbyvid( vid )) == NULL ) {
359         return( AFPERR_PARAM );
360     }
361
362     if (vol->v_flags & AFPVOL_RO)
363         return AFPERR_VLOCK;
364
365     memcpy( &did, ibuf, sizeof( did ));
366     ibuf += sizeof( int );
367     if (( dir = dirsearch( vol, did )) == NULL ) {
368         return( AFPERR_NOOBJ );
369     }
370
371     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
372         return( AFPERR_NOOBJ );
373     }
374
375     if ( *path == '\0' ) {
376         rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ);
377     } else if (of_findname(vol, curdir, path)) {
378         rc = AFPERR_BUSY;
379     } else if ((rc = deletefile( upath = mtoupath(vol, path ))) == AFP_OK) {
380 #if AD_VERSION > AD_VERSION1 /* get rid of entry */
381         cnid_t id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
382         cnid_delete(vol->v_db, id);
383 #endif
384     }
385     if ( rc == AFP_OK ) {
386         setvoltime(obj, vol );
387     }
388     return( rc );
389 }
390
391 char *ctoupath( vol, dir, name )
392     const struct vol    *vol;
393     struct dir  *dir;
394     char        *name;
395 {
396     struct dir  *d;
397     static char path[ MAXPATHLEN + 1];
398     char        *p, *u;
399     int         len;
400
401     p = path + sizeof( path ) - 1;
402     *p = '\0';
403     u = mtoupath(vol, name );
404     len = strlen( u );
405     p -= len;
406     strncpy( p, u, len );
407     for ( d = dir; d->d_parent; d = d->d_parent ) {
408         *--p = '/';
409         u = mtoupath(vol, d->d_name );
410         len = strlen( u );
411         p -= len;
412         strncpy( p, u, len );
413     }
414     *--p = '/';
415     len = strlen( vol->v_path );
416     p -= len;
417     strncpy( p, vol->v_path, len );
418
419     return( p );
420 }
421
422
423 int afp_moveandrename(obj, ibuf, ibuflen, rbuf, rbuflen )
424     AFPObj      *obj;
425     char        *ibuf, *rbuf;
426     int         ibuflen, *rbuflen;
427 {
428     struct vol  *vol;
429     struct dir  *sdir, *ddir, *odir = NULL;
430     struct stat st;
431     char        *oldname, *newname;
432     char        *path, *p, *upath; 
433     int         did, rc;
434     int         plen;
435     u_int16_t   vid;
436 #if AD_VERSION > AD_VERSION1
437     cnid_t      id;
438 #endif
439 #ifdef DROPKLUDGE
440     struct stat sb;
441     struct dir  *dir;
442     char        adpath[50];
443     int         uid;
444 #endif DROPKLUDGE
445
446     *rbuflen = 0;
447     ibuf += 2;
448
449     memcpy( &vid, ibuf, sizeof( vid ));
450     ibuf += sizeof( vid );
451     if (( vol = getvolbyvid( vid )) == NULL ) {
452         return( AFPERR_PARAM );
453     }
454
455     if (vol->v_flags & AFPVOL_RO)
456         return AFPERR_VLOCK;
457
458     /* source did followed by dest did */
459     memcpy( &did, ibuf, sizeof( did ));
460     ibuf += sizeof( int );
461     if (( sdir = dirsearch( vol, did )) == NULL ) {
462         return( AFPERR_PARAM );
463     }
464
465     memcpy( &did, ibuf, sizeof( did ));
466     ibuf += sizeof( int );
467
468     /* source pathname */
469     if (( path = cname( vol, sdir, &ibuf )) == NULL ) {
470         return( AFPERR_NOOBJ );
471     }
472
473     sdir = curdir;
474     newname = obj->newtmp;
475     oldname = obj->oldtmp;
476     if ( *path != '\0' ) {
477         /* not a directory */
478         strcpy(newname, path);
479         strcpy(oldname, path); /* an extra copy for of_rename */
480 #if AD_VERSION > AD_VERSION1
481         p = mtoupath(vol, path);
482         id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p));
483 #endif
484         p = ctoupath( vol, sdir, newname );
485     } else {
486         odir = curdir;
487         strcpy( newname, odir->d_name );
488         strcpy(oldname, odir->d_name); 
489         p = ctoupath( vol, odir->d_parent, newname );
490 #if AD_VERSION > AD_VERSION1
491         id = curdir->d_did; /* we already have the CNID */
492 #endif
493     }
494     /*
495      * p now points to the full pathname of the source fs object.
496      */
497
498     /* get the destination directory */
499     if (( ddir = dirsearch( vol, did )) == NULL ) {
500         return( AFPERR_PARAM );
501     }
502     if (( path = cname( vol, ddir, &ibuf )) == NULL ) {
503         return( AFPERR_NOOBJ );
504     }
505     if ( *path != '\0' ) {
506         return( AFPERR_BADTYPE );
507     }
508
509     /* one more place where we know about path type */
510     if ( *ibuf++ != 2 ) {
511         return( AFPERR_PARAM );
512     }
513
514     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
515         strncpy( newname, ibuf, plen );
516         newname[ plen ] = '\0';
517     }
518
519     /* check for illegal characters */
520     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
521         strpbrk(newname, MSWINDOWS_BADCHARS))
522         return AFPERR_PARAM;
523
524     upath = mtoupath(vol, newname);
525
526     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
527       return AFPERR_PARAM;
528
529     if (!validupath(vol, upath))
530       return AFPERR_EXIST;
531
532     /* source == destination. we just silently accept this. */
533     if (curdir == sdir) {
534       if (strcmp(oldname, newname) == 0)
535         return AFP_OK;
536       
537       /* deal with case insensitive, case-preserving filesystems. */
538       if ((stat(upath, &st) == 0) && strdiacasecmp(oldname, newname)) 
539         return AFPERR_EXIST;
540       
541     } else if (stat(upath, &st ) == 0)
542       return( AFPERR_EXIST );
543       
544     if ( !odir ) {
545       if (of_findname(vol, curdir, newname)) {
546         rc = AFPERR_BUSY;
547       } else if ((rc = renamefile( p, upath, newname, 
548                                    vol_noadouble(vol) )) == AFP_OK) {
549         /* if it's still open, rename the ofork as well. */
550         rc = of_rename(vol, sdir, oldname, curdir, newname);
551       }
552     } else {
553         rc = renamedir(p, upath, odir, curdir, newname, vol_noadouble(vol));
554     }
555 #ifdef DROPKLUDGE
556         strcpy (adpath, "./.AppleDouble/");
557         strcat (adpath, newname);
558         if (( dir = dirsearch( vol, did )) == NULL ) {
559           syslog (LOG_ERR, "afp_moveandrename: Unable to get directory info.");
560           return( AFPERR_NOOBJ );
561         }
562         else
563         if (stat(".", &sb) < 0) {
564           syslog (LOG_ERR, "afp_moveandrename: Error checking directory \"%s\": %m", dir->d_name);
565           return(-1);
566         }
567         else {
568           uid=geteuid();
569           if ( uid != sb.st_uid )
570           {
571             seteuid(0);
572             if (lchown(newname, sb.st_uid, sb.st_gid) < 0)
573             {
574               syslog (LOG_ERR, "afp_moveandrename: Error changing owner/gid of %s: %m", p);
575               return (-1);
576             }
577             if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
578             {
579               syslog (LOG_ERR, "afp_moveandrename: Error changing AppleDouble owner/gid %s: %m", adpath);
580               return (-1);
581             }
582           }
583           else
584             syslog (LOG_DEBUG, "No ownership change necessary.");
585         }
586         seteuid(uid); /* Restore process ownership to normal */
587 #endif DROPKLUDGE
588
589     if ( rc == AFP_OK ) {
590 #if AD_VERSION > AD_VERSION1
591         /* renaming may have moved the file/dir across a filesystem */
592         if (stat(newname, &st) < 0) 
593           return AFPERR_MISC;
594         
595         /* fix up the catalog entry */
596         cnid_update(vol->v_db, id, &st, curdir->d_did, newname, strlen(newname));
597 #endif      
598         setvoltime(obj, vol );
599     }
600     return( rc );
601 }
602