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