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