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