]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
af6da8b13d56c5aeaac09f306ffd2424f38d3210
[netatalk.git] / etc / afpd / file.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <utime.h>
11 #include <fcntl.h>
12 #include <dirent.h>
13 #include <sys/mman.h>
14 #include <errno.h>
15
16 #include <sys/syslog.h>
17 #include <sys/types.h>
18 #include <sys/time.h>
19 #include <sys/param.h>
20 #include <sys/stat.h>
21
22 #include <netatalk/endian.h>
23 #include <atalk/adouble.h>
24 #include <atalk/afp.h>
25 #include <atalk/util.h>
26 #include <atalk/cnid.h>
27
28 #include "directory.h"
29 #include "desktop.h"
30 #include "volume.h"
31 #include "fork.h"
32 #include "file.h"
33 #include "filedir.h"
34 #include "globals.h"
35
36 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
37  * field         bytes        subfield    bytes
38  * 
39  * files:
40  * ioFlFndrInfo  16      ->       type    4  type field
41  *                             creator    4  creator field
42  *                               flags    2  finder flags: 
43  *                                           alias, bundle, etc.
44  *                            location    4  location in window
45  *                              folder    2  window that contains file
46  * 
47  * ioFlXFndrInfo 16      ->     iconID    2  icon id
48  *                              unused    6  reserved 
49  *                              script    1  script system
50  *                              xflags    1  reserved
51  *                           commentID    2  comment id
52  *                           putawayID    4  home directory id
53  */
54
55 const u_char ufinderi[] = {
56     'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
57     0, 0, 0, 0, 0, 0, 0, 0, 
58     0, 0, 0, 0, 0, 0, 0, 0,
59     0, 0, 0, 0, 0, 0, 0, 0
60 };
61
62 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
63     struct vol  *vol;
64     u_int16_t   bitmap;
65     char        *path;
66     struct dir  *dir;
67     struct stat *st;
68     char        *buf;
69     int         *buflen;
70 {
71     struct stat         hst, lst, *lstp;
72     struct adouble      ad, *adp;
73     struct ofork        *of;
74     struct extmap       *em;
75     char                *data, *nameoff = NULL, *upath;
76     int                 bit = 0, isad = 1, aint;
77     u_int16_t           ashort;
78     u_char              achar, fdType[4];
79
80     upath = mtoupath(vol, path);
81     if ((of = of_findname(vol, curdir, path))) {
82       adp = of->of_ad;
83     } else {
84       memset(&ad, 0, sizeof(ad));
85       adp = &ad;
86     }
87
88     if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
89         isad = 0;
90     } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
91             syslog( LOG_ERR, "getfilparams fstat: %m" );
92     }
93
94     data = buf;
95     while ( bitmap != 0 ) {
96         while (( bitmap & 1 ) == 0 ) {
97             bitmap = bitmap>>1;
98             bit++;
99         }
100
101         switch ( bit ) {
102         case FILPBIT_ATTR :
103             if ( isad ) {
104                 ad_getattr(adp, &ashort);
105             } else if (*upath == '.') {
106                 ashort = htons(ATTRBIT_INVISIBLE);
107             } else
108                 ashort = 0;
109             memcpy(data, &ashort, sizeof( ashort ));
110             data += sizeof( u_short );
111             break;
112
113         case FILPBIT_PDID :
114             memcpy(data, &dir->d_did, sizeof( int ));
115             data += sizeof( int );
116             break;
117
118         case FILPBIT_CDATE :
119             if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
120                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
121             memcpy(data, &aint, sizeof( aint ));
122             data += sizeof( aint );
123             break;
124
125         case FILPBIT_MDATE :
126             if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
127                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) && 
128                     (hst.st_mtime < st->st_mtime)) {
129                     aint = AD_DATE_FROM_UNIX(st->st_mtime);
130                 }
131             } else {
132                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
133             }
134             memcpy(data, &aint, sizeof( int ));
135             data += sizeof( int );
136             break;
137
138         case FILPBIT_BDATE :
139             if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
140                 aint = AD_DATE_START;
141             memcpy(data, &aint, sizeof( int ));
142             data += sizeof( int );
143             break;
144
145         case FILPBIT_FINFO :
146             if (isad) 
147               memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
148             else {
149               memcpy(data, ufinderi, 32);
150               if (*upath == '.') { /* make it invisible */
151                 ashort = htons(FINDERINFO_INVISIBLE);
152                 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
153               }
154             } 
155
156             if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
157                                   ufinderi, 8 ) == 0)) &&
158                 (em = getextmap( path ))) {
159               memcpy(data, em->em_type, sizeof( em->em_type ));
160               memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
161             }
162             data += 32;
163             break;
164
165         case FILPBIT_LNAME :
166             nameoff = data;
167             data += sizeof( u_int16_t );
168             break;
169
170         case FILPBIT_SNAME :
171             memset(data, 0, sizeof(u_int16_t));
172             data += sizeof( u_int16_t );
173             break;
174
175         case FILPBIT_FNUM :
176 #if AD_VERSION > AD_VERSION1
177           /* use the CNID database if we're using AD v2 */
178             if (isad)
179               memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
180             else
181               aint = 0;
182
183             if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath, 
184                                   strlen(upath), aint))) {
185 #endif
186             /*
187              * What a fucking mess.  First thing:  DID and FNUMs are
188              * in the same space for purposes of enumerate (and several
189              * other wierd places).  While we consider this Apple's bug,
190              * this is the work-around:  In order to maintain constant and
191              * unique DIDs and FNUMs, we monotonically generate the DIDs
192              * during the session, and derive the FNUMs from the filesystem.
193              * Since the DIDs are small, we insure that the FNUMs are fairly
194              * large by setting thier high bits to the device number.
195              *
196              * AFS already does something very similar to this for the
197              * inode number, so we don't repeat the procedure.
198              *
199              * new algorithm:
200              * due to complaints over did's being non-persistent,
201              * here's the current hack to provide semi-persistent
202              * did's: 
203              *      1) we reserve the first bit for file ids.
204              *      2) the next 7 bits are for the device.
205              *      3) the remaining 24 bits are for the inode.
206              *
207              * both the inode and device information are actually hashes
208              * that are then truncated to the requisite bit length.
209              *
210              * it should be okay to use lstat to deal with symlinks.
211              */
212               lstp = (lstat(upath, &lst) < 0) ? st : &lst;
213               aint = htonl(CNID(lstp, 1));
214 #if AD_VERSION > AD_VERSION1
215             }
216 #endif
217             memcpy(data, &aint, sizeof( aint ));
218             data += sizeof( aint );
219             break;
220
221         case FILPBIT_DFLEN :
222             aint = htonl( st->st_size );
223             memcpy(data, &aint, sizeof( aint ));
224             data += sizeof( aint );
225             break;
226
227         case FILPBIT_RFLEN :
228             if ( isad ) {
229                 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
230             } else {
231                 aint = 0;
232             }
233             memcpy(data, &aint, sizeof( aint ));
234             data += sizeof( aint );
235             break;
236
237             /* Current client needs ProDOS info block for this file.
238                Use simple heuristic and let the Mac "type" string tell
239                us what the PD file code should be.  Everything gets a
240                subtype of 0x0000 unless the original value was hashed
241                to "pXYZ" when we created it.  See IA, Ver 2.
242                <shirsch@ibm.net> */
243         case FILPBIT_PDINFO :
244             if ( isad ) {
245               memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
246               
247               if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
248                 achar = '\x04';
249                 ashort = 0x0000;
250               }
251               else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
252                 achar = '\xff';
253                 ashort = 0x0000;
254               }
255               else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
256                 achar = '\xb3';
257                 ashort = 0x0000;
258               }
259               else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
260                 achar = '\x00';
261                 ashort = 0x0000;
262               }
263               else if ( fdType[0] == 'p' ) {
264                 achar = fdType[1];
265                 ashort = (fdType[2] * 256) + fdType[3];
266               } 
267               else {
268                 achar = '\x00';
269                 ashort = 0x0000;
270               }
271             } 
272             else {
273               achar = '\x00';
274               ashort = 0x0000;
275             }
276             
277             *data++ = achar;
278             *data++ = 0;
279             memcpy(data, &ashort, sizeof( ashort ));
280             data += sizeof( ashort );
281             memset(data, 0, sizeof( ashort ));
282             data += sizeof( ashort );
283             break;
284
285         default :
286             if ( isad ) {
287                 ad_close( adp, ADFLAGS_HF );
288             }
289             return( AFPERR_BITMAP );
290         }
291         bitmap = bitmap>>1;
292         bit++;
293     }
294     if ( nameoff ) {
295         ashort = htons( data - buf );
296         memcpy(nameoff, &ashort, sizeof( ashort ));
297         if ((aint = strlen( path )) > MACFILELEN)
298           aint = MACFILELEN;
299         *data++ = aint;
300         memcpy(data, path, aint );
301         data += aint;
302     }
303     if ( isad ) {
304         ad_close( adp, ADFLAGS_HF );
305     }
306     *buflen = data - buf;
307     return( AFP_OK );
308 }
309
310 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
311     AFPObj      *obj;
312     char        *ibuf, *rbuf;
313     int         ibuflen, *rbuflen;
314 {
315     struct stat         st;
316     struct adouble      ad, *adp;
317     struct vol          *vol;
318     struct dir          *dir;
319     struct ofork        *of;
320     char                *path, *upath;
321     int                 creatf, did, openf;
322     u_int16_t           vid;
323
324     *rbuflen = 0;
325     ibuf++;
326     creatf = (unsigned char) *ibuf++;
327
328     memcpy(&vid, ibuf, sizeof( vid ));
329     ibuf += sizeof( vid );
330
331     if (( vol = getvolbyvid( vid )) == NULL ) {
332         return( AFPERR_PARAM );
333     }
334
335     if (vol->v_flags & AFPVOL_RO)
336         return AFPERR_VLOCK;
337
338     memcpy(&did, ibuf, sizeof( did));
339     ibuf += sizeof( did );
340
341     if (( dir = dirsearch( vol, did )) == NULL ) {
342         return( AFPERR_NOOBJ );
343     }
344
345     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
346         return( AFPERR_NOOBJ );
347     }
348
349     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
350         strpbrk(path, MSWINDOWS_BADCHARS))
351         return AFPERR_PARAM;
352
353     upath = mtoupath(vol, path);
354
355     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
356       return AFPERR_PARAM;
357
358     if (!validupath(vol, upath))
359       return AFPERR_EXIST;
360
361     if ((of = of_findname(vol, curdir, path))) {
362       adp = of->of_ad;
363     } else {
364       memset(&ad, 0, sizeof(ad));
365       adp = &ad;
366     }
367     if ( creatf) {
368         /* on a hard create, fail if file exists and is open */
369         if ((stat(upath, &st) == 0) && of)
370           return AFPERR_BUSY;
371         openf = O_RDWR|O_CREAT|O_TRUNC;
372     } else {
373         openf = O_RDWR|O_CREAT|O_EXCL;
374     }
375
376     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
377                   openf, 0666, adp) < 0 ) {
378       switch ( errno ) {
379         case EEXIST :
380             return( AFPERR_EXIST );
381         case EACCES :
382             return( AFPERR_ACCESS );
383         case ENOENT:
384             /* on noadouble volumes, just creating the data fork is ok */
385             if (vol_noadouble(vol) && (stat(upath, &st) == 0))
386               goto createfile_done;
387             /* fallthrough */
388         default :
389             return( AFPERR_PARAM );
390         }
391     }
392
393     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
394     memcpy(ad_entry( adp, ADEID_NAME ), path, 
395            ad_getentrylen( adp, ADEID_NAME ));
396     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
397     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
398
399 createfile_done:
400     setvoltime(obj, vol );
401     return AFP_OK;
402 }
403
404 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
405     AFPObj      *obj;
406     char        *ibuf, *rbuf;
407     int         ibuflen, *rbuflen;
408 {
409     struct vol  *vol;
410     struct dir  *dir;
411     char        *path;
412     int         did, rc;
413     u_int16_t   vid, bitmap;
414
415     *rbuflen = 0;
416     ibuf += 2;
417
418     memcpy(&vid, ibuf, sizeof( vid ));
419     ibuf += sizeof( vid );
420     if (( vol = getvolbyvid( vid )) == NULL ) {
421         return( AFPERR_PARAM );
422     }
423
424     if (vol->v_flags & AFPVOL_RO)
425         return AFPERR_VLOCK;
426
427     memcpy(&did, ibuf, sizeof( did ));
428     ibuf += sizeof( did );
429     if (( dir = dirsearch( vol, did )) == NULL ) {
430         return( AFPERR_NOOBJ );
431     }
432
433     memcpy(&bitmap, ibuf, sizeof( bitmap ));
434     bitmap = ntohs( bitmap );
435     ibuf += sizeof( bitmap );
436
437     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
438         return( AFPERR_NOOBJ );
439     }
440
441     if ((u_long)ibuf & 1 ) {
442         ibuf++;
443     }
444
445     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
446         setvoltime(obj, vol );
447     }
448
449     return( rc );
450 }
451
452
453 int setfilparams(vol, path, bitmap, buf )
454     struct vol  *vol;
455     char        *path, *buf;
456     u_int16_t   bitmap;
457 {
458     struct adouble      ad, *adp;
459     struct ofork        *of;
460     struct extmap       *em;
461     int                 bit = 0, isad = 1, err = AFP_OK;
462     char                *upath;
463     u_char              achar, *fdType, xyy[4];
464     u_int16_t           ashort, bshort;
465     u_int32_t           aint;
466     struct utimbuf      ut;
467
468     upath = mtoupath(vol, path);
469     if ((of = of_findname(vol, curdir, path))) {
470       adp = of->of_ad;
471     } else {
472       memset(&ad, 0, sizeof(ad));
473       adp = &ad;
474     }
475     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, 
476                  O_RDWR|O_CREAT, 0666, adp) < 0) {
477       /* for some things, we don't need an adouble header */
478       if (bitmap & ~(1<<FILPBIT_MDATE)) {
479         return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
480       }
481       isad = 0;
482     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
483         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
484         memcpy(ad_entry( adp, ADEID_NAME ), path, 
485                ad_getentrylen( adp, ADEID_NAME ));
486     }
487
488     while ( bitmap != 0 ) {
489         while (( bitmap & 1 ) == 0 ) {
490             bitmap = bitmap>>1;
491             bit++;
492         }
493
494         switch(  bit ) {
495         case FILPBIT_ATTR :
496             memcpy(&ashort, buf, sizeof( ashort ));
497             ad_getattr(adp, &bshort);
498             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
499               bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
500             } else {
501               bshort &= ~ashort;
502             }
503             ad_setattr(adp, bshort);
504             buf += sizeof( ashort );
505             break;
506
507         case FILPBIT_CDATE :
508             memcpy(&aint, buf, sizeof(aint));
509             ad_setdate(adp, AD_DATE_CREATE, aint);
510             buf += sizeof( aint );
511             break;
512
513         case FILPBIT_MDATE :
514             memcpy(&aint, buf, sizeof( aint ));
515             if (isad)
516               ad_setdate(adp, AD_DATE_MODIFY, aint);
517             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
518             utime(upath, &ut);
519             buf += sizeof( aint );
520             break;
521
522         case FILPBIT_BDATE :
523             memcpy(&aint, buf, sizeof(aint));
524             ad_setdate(adp, AD_DATE_BACKUP, aint);
525             buf += sizeof( aint );
526             break;
527
528         case FILPBIT_FINFO :
529             if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
530                 && (em = getextmap( path )) && 
531                 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
532                 (memcmp(buf + 4, em->em_creator,
533                         sizeof( em->em_creator )) == 0)) {
534               memcpy(buf, ufinderi, 8 );
535             }
536             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
537             buf += 32;
538             break;
539
540             /* Client needs to set the ProDOS file info for this file.
541                Use defined strings for the simple cases, and convert
542                all else into pXYY per Inside Appletalk.  Always set
543                the creator as "pdos". <shirsch@ibm.net> */
544         case FILPBIT_PDINFO :
545             achar = *buf;
546             buf += 2;
547             memcpy(&ashort, buf, sizeof( ashort ));
548             ashort = ntohs( ashort );
549             buf += 2;
550  
551             switch ( (unsigned int) achar )
552               {
553               case 0x04 :
554                 fdType = ( u_char *) "TEXT";
555                 break;
556                 
557               case 0xff :
558                 fdType = ( u_char *) "PSYS";
559                 break;
560  
561               case 0xb3 :
562                 fdType = ( u_char *) "PS16";
563                 break;
564  
565               case 0x00 :
566                 fdType = ( u_char *) "BINA";
567                 break;
568  
569               default :
570                 xyy[0] = ( u_char ) 'p';
571                 xyy[1] = achar;
572                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
573                 xyy[3] = ( u_char ) ashort & 0xff;
574                 fdType = xyy;
575                 break;
576               }
577             
578             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
579             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
580             break;
581  
582
583         default :
584             err = AFPERR_BITMAP;
585             goto setfilparam_done;
586         }
587
588         bitmap = bitmap>>1;
589         bit++;
590     }
591
592 setfilparam_done:
593     if (isad) {
594       ad_flush( adp, ADFLAGS_HF );
595       ad_close( adp, ADFLAGS_HF );
596     }
597     return err;
598 }
599
600 /*
601  * renamefile and copyfile take the old and new unix pathnames
602  * and the new mac name.
603  * NOTE: if we have to copy a file instead of renaming it, locks
604  *       will break.
605  */
606 int renamefile(src, dst, newname, noadouble )
607     char        *src, *dst, *newname;
608     const int         noadouble;
609 {
610     struct adouble      ad;
611     char                adsrc[ MAXPATHLEN + 1];
612     int                 len, rc;
613
614     /*
615      * Note that this is only checking the existance of the data file,
616      * not the header file.  The thinking is that if the data file doesn't
617      * exist, but the header file does, the right thing to do is remove
618      * the data file silently.
619      */
620
621     /* existence check moved to afp_moveandrename */
622
623     if ( rename( src, dst ) < 0 ) {
624         switch ( errno ) {
625         case ENOENT :
626             return( AFPERR_NOOBJ );
627         case EPERM:
628         case EACCES :
629             return( AFPERR_ACCESS );
630         case EROFS:
631             return AFPERR_VLOCK;
632         case EXDEV :                    /* Cross device move -- try copy */
633             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
634                 deletefile( dst );
635                 return( rc );
636             }
637             return deletefile( src );
638         default :
639             return( AFPERR_PARAM );
640         }
641     }
642
643     strcpy( adsrc, ad_path( src, 0 ));
644     rc = 0;
645 rename_retry:
646     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
647         struct stat st;
648
649         switch ( errno ) {
650         case ENOENT :
651           /* check for a source appledouble header. if it exists, make
652            * a dest appledouble directory and do the rename again. */
653           memset(&ad, 0, sizeof(ad));
654           if (rc || stat(adsrc, &st) ||
655               (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
656             return AFP_OK;
657           rc++;
658           ad_close(&ad, ADFLAGS_HF);
659           goto rename_retry;
660         case EPERM:
661         case EACCES :
662             return( AFPERR_ACCESS );
663         case EROFS:
664             return AFPERR_VLOCK;
665         default :
666             return( AFPERR_PARAM );
667         }
668     }
669
670     memset(&ad, 0, sizeof(ad));
671     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
672         switch ( errno ) {
673         case ENOENT :
674             return( AFPERR_NOOBJ );
675         case EACCES :
676             return( AFPERR_ACCESS );
677         case EROFS:
678             return AFPERR_VLOCK;
679         default :
680             return( AFPERR_PARAM );
681         }
682     }
683
684     len = strlen( newname );
685     ad_setentrylen( &ad, ADEID_NAME, len );
686     memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
687     ad_flush( &ad, ADFLAGS_HF );
688     ad_close( &ad, ADFLAGS_HF );
689
690     return( AFP_OK );
691 }
692
693 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
694     AFPObj      *obj;
695     char        *ibuf, *rbuf;
696     int         ibuflen, *rbuflen;
697 {
698     struct vol  *vol;
699     struct dir  *dir;
700     char        *newname, *path, *p;
701     u_int32_t   sdid, ddid;
702     int         plen, err;
703     u_int16_t   svid, dvid;
704
705     *rbuflen = 0;
706     ibuf += 2;
707
708     memcpy(&svid, ibuf, sizeof( svid ));
709     ibuf += sizeof( svid );
710     if (( vol = getvolbyvid( svid )) == NULL ) {
711         return( AFPERR_PARAM );
712     }
713
714     memcpy(&sdid, ibuf, sizeof( sdid ));
715     ibuf += sizeof( sdid );
716     if (( dir = dirsearch( vol, sdid )) == NULL ) {
717         return( AFPERR_PARAM );
718     }
719
720     memcpy(&dvid, ibuf, sizeof( dvid ));
721     ibuf += sizeof( dvid );
722     memcpy(&ddid, ibuf, sizeof( ddid ));
723     ibuf += sizeof( ddid );
724
725     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
726         return( AFPERR_NOOBJ );
727     }
728     if ( *path == '\0' ) {
729         return( AFPERR_BADTYPE );
730     }
731
732     /* don't allow copies when the file is open.
733      * XXX: the spec only calls for read/deny write access.
734      *      however, copyfile doesn't have any of that info,
735      *      and locks need to stay coherent. as a result,
736      *      we just balk if the file is opened already. */
737     if (of_findname(vol, curdir, path))
738       return AFPERR_DENYCONF;
739     
740     newname = obj->newtmp;
741     strcpy( newname, path );
742
743     p = ctoupath( vol, curdir, newname );
744
745     if (( vol = getvolbyvid( dvid )) == NULL ) {
746         return( AFPERR_PARAM );
747     }
748
749     if (vol->v_flags & AFPVOL_RO)
750         return AFPERR_VLOCK;
751
752     if (( dir = dirsearch( vol, ddid )) == NULL ) {
753         return( AFPERR_PARAM );
754     }
755
756     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
757         return( AFPERR_NOOBJ );
758     }
759     if ( *path != '\0' ) {
760         return( AFPERR_BADTYPE );
761     }
762
763     /* one of the handful of places that knows about the path type */
764     if ( *ibuf++ != 2 ) {
765         return( AFPERR_PARAM );
766     }
767     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
768         strncpy( newname, ibuf, plen );
769         newname[ plen ] = '\0';
770     }
771
772     if ( (err = copyfile(p, mtoupath(vol, newname ), newname, 
773                   vol_noadouble(vol))) < 0 ) {
774         return err;
775     }
776
777     setvoltime(obj, vol );
778     return( AFP_OK );
779 }
780
781
782 static __inline__ int copy_all(const int dfd, const void *buf,
783                                size_t buflen)
784 {
785   ssize_t cc;
786
787   while (buflen > 0) {
788     if ((cc = write(dfd, buf, buflen)) < 0) {
789       switch (errno) {
790       case EINTR:
791         continue;
792       case EDQUOT:
793       case EFBIG:
794       case ENOSPC:
795         return AFPERR_DFULL;
796       case EROFS:
797         return AFPERR_VLOCK;
798       default:
799         return AFPERR_PARAM;
800       }
801     }
802     buflen -= cc;
803   }
804
805   return 0;
806 }
807
808 /* XXX: this needs to use ad_open and ad_lock. so, we need to
809  * pass in vol and path */
810 int copyfile(src, dst, newname, noadouble )
811     char        *src, *dst, *newname;
812     const int   noadouble;
813 {
814     struct adouble      ad;
815     struct stat         st;
816     char                filebuf[8192];
817     int                 sfd, dfd, len, err = AFP_OK;
818     ssize_t             cc;
819
820
821     if (newname) { 
822       if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
823         switch ( errno ) {
824         case ENOENT :
825             break; /* just copy the data fork */
826         case EACCES :
827             return( AFPERR_ACCESS );
828         default :
829             return( AFPERR_PARAM );
830         }
831       } else {
832         if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
833                 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
834             close( sfd );
835             switch ( errno ) {
836             case ENOENT :
837                 return( AFPERR_NOOBJ );
838             case EACCES :
839                 return( AFPERR_ACCESS );
840             case EROFS:
841                 return AFPERR_VLOCK;
842             default :
843                 return( AFPERR_PARAM );
844             }
845         }
846
847         /* copy the file */
848 #ifdef SENDFILE_FLAVOR_LINUX
849         if (fstat(sfd, &st) == 0) {
850           if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
851             switch (errno) {
852             case EDQUOT:
853             case EFBIG:
854             case ENOSPC:
855               err = AFPERR_DFULL;
856               break;
857             case EROFS:
858               err = AFPERR_VLOCK;
859               break;
860             default:
861               err = AFPERR_PARAM;
862             }
863           }
864           goto copyheader_done;
865         }
866 #endif
867         while (1) {
868           if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
869             if (errno == EINTR) 
870               continue;
871             err = AFPERR_PARAM;
872             break;
873           }
874
875           if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
876             break;
877         }
878
879 copyheader_done:
880         close(sfd);
881         close(dfd);
882         if (err < 0) {
883           unlink(ad_path(dst, ADFLAGS_HF));
884           return err;
885         }
886       }
887     }
888
889     /* data fork copying */
890     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
891         switch ( errno ) {
892         case ENOENT :
893             return( AFPERR_NOOBJ );
894         case EACCES :
895             return( AFPERR_ACCESS );
896         default :
897             return( AFPERR_PARAM );
898         }
899     }
900
901     if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
902         close( sfd );
903         switch ( errno ) {
904         case ENOENT :
905             return( AFPERR_NOOBJ );
906         case EACCES :
907             return( AFPERR_ACCESS );
908         case EROFS:
909             return AFPERR_VLOCK;
910         default :
911             return( AFPERR_PARAM );
912         }
913     }
914
915 #ifdef SENDFILE_FLAVOR_LINUX
916     if (fstat(sfd, &st) == 0) {
917       if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
918         switch (errno) {
919         case EDQUOT:
920         case EFBIG:
921         case ENOSPC:
922           err = AFPERR_DFULL;
923           break;
924         default:
925           err = AFPERR_PARAM;
926         }
927       }
928       goto copydata_done;
929     }
930 #endif
931
932     while (1) {
933       if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
934         if (errno == EINTR)
935           continue;
936         
937         err = AFPERR_PARAM;
938         break;
939       }
940       
941       if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
942         break;
943       }
944     }
945     
946 copydata_done:
947     close(sfd);
948     close(dfd);
949     if (err < 0) {
950       unlink(ad_path(dst, ADFLAGS_HF));
951       unlink(dst);
952       return err;
953     }
954     
955     if (newname) {
956       memset(&ad, 0, sizeof(ad));
957       if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
958                     0666, &ad) < 0 ) {
959         switch ( errno ) {
960         case ENOENT :
961           return noadouble ? AFP_OK : AFPERR_NOOBJ;
962         case EACCES :
963           return( AFPERR_ACCESS );
964         case EROFS:
965           return AFPERR_VLOCK;
966         default :
967           return( AFPERR_PARAM );
968         }
969       }
970
971       len = strlen( newname );
972       ad_setentrylen( &ad, ADEID_NAME, len );
973       memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
974       ad_flush( &ad, ADFLAGS_HF );
975       ad_close( &ad, ADFLAGS_HF );
976     }
977     
978     return( AFP_OK );
979 }
980
981
982 int deletefile( file )
983     char                *file;
984 {
985     struct adouble      ad;
986     int                 adflags, err = AFP_OK;
987
988     /* try to open both at once */
989     adflags = ADFLAGS_DF|ADFLAGS_HF;
990     memset(&ad, 0, sizeof(ad));
991     if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
992           switch (errno) {
993           case ENOENT:
994             adflags = ADFLAGS_DF;
995             /* that failed. now try to open just the data fork */
996             memset(&ad, 0, sizeof(ad));
997             if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
998               switch (errno) {
999               case ENOENT:
1000                 return AFPERR_NOOBJ;
1001               case EACCES:
1002                 return AFPERR_ACCESS;
1003               default:
1004                 return AFPERR_PARAM;
1005               }
1006             }
1007             break;
1008
1009           case EACCES:
1010             return( AFPERR_ACCESS );
1011           case EROFS:
1012             return AFPERR_VLOCK;
1013           default:
1014             return( AFPERR_PARAM );
1015           }
1016     }
1017
1018     if ((adflags & ADFLAGS_HF) &&
1019         (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1020       ad_close( &ad, adflags );
1021       return( AFPERR_BUSY );
1022     }
1023
1024     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1025       err = AFPERR_BUSY;
1026       goto delete_unlock;
1027     }
1028
1029     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1030         switch ( errno ) {
1031         case EPERM:
1032         case EACCES :
1033             err = AFPERR_ACCESS;
1034             goto delete_unlock;
1035         case EROFS:
1036             err = AFPERR_VLOCK;
1037             goto delete_unlock;
1038         case ENOENT :
1039             break;
1040         default :
1041             err = AFPERR_PARAM;
1042             goto delete_unlock;
1043         }
1044     }
1045
1046     if ( unlink( file ) < 0 ) {
1047         switch ( errno ) {
1048         case EPERM:
1049         case EACCES :
1050             err = AFPERR_ACCESS;
1051             break;
1052         case EROFS:
1053             err = AFPERR_VLOCK;
1054             break;
1055         case ENOENT :
1056             break;
1057         default :
1058             err = AFPERR_PARAM;
1059             break;
1060         }
1061     }
1062
1063 delete_unlock:
1064     if (adflags & ADFLAGS_HF)
1065       ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1066     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1067     ad_close( &ad, adflags );
1068     return err;
1069 }
1070
1071
1072 #if AD_VERSION > AD_VERSION1
1073 /* return a file id */
1074 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1075     AFPObj      *obj;
1076     char        *ibuf, *rbuf;
1077     int         ibuflen, *rbuflen;
1078 {
1079     struct stat         st;
1080     struct adouble      ad;
1081     struct vol          *vol;
1082     struct dir          *dir;
1083     char                *path, *upath;
1084     int                 len;
1085     cnid_t              did, id;
1086     u_short             vid;
1087     
1088
1089     *rbuflen = 0;
1090     ibuf += 2;
1091
1092     memcpy(&vid, ibuf, sizeof(vid));
1093     ibuf += sizeof(vid);
1094
1095     if (( vol = getvolbyvid( vid )) == NULL ) {
1096         return( AFPERR_PARAM);
1097     }
1098
1099     if (vol->v_flags & AFPVOL_RO)
1100         return AFPERR_VLOCK;
1101
1102     memcpy(&did, ibuf, sizeof( did ));
1103     ibuf += sizeof(did);
1104
1105     if (( dir = dirsearch( vol, did )) == NULL ) {
1106         return( AFPERR_PARAM );
1107     }
1108
1109     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1110         return( AFPERR_PARAM );
1111     }
1112
1113     if ( *path == '\0' ) {
1114         return( AFPERR_BADTYPE );
1115     }
1116
1117     upath = mtoupath(vol, path);
1118     if (stat(upath, &st) < 0) {
1119       switch (errno) {
1120       case EPERM:
1121       case EACCES:
1122         return AFPERR_ACCESS;
1123       case ENOENT:
1124         return AFPERR_NOOBJ;
1125       default:
1126         return AFPERR_PARAM;
1127       }
1128     }
1129
1130     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1131       memcpy(rbuf, &id, sizeof(id));
1132       *rbuflen = sizeof(id);
1133       return AFPERR_EXISTID;
1134     }
1135
1136     memset(&ad, 0, sizeof(ad));
1137     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1138       id = 0;
1139     else {
1140       memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1141       ad_close(upath, ADFLAGS_HF);
1142     }
1143
1144     if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1145       memcpy(rbuf, &id, sizeof(id));
1146       *rbuflen = sizeof(id);
1147       return AFP_OK;
1148     }
1149
1150     switch (errno) {
1151     case EROFS:
1152       return AFPERR_VLOCK;
1153       break;
1154     case EPERM:
1155     case EACCES:
1156       return AFPERR_ACCESS;
1157       break;
1158     default:
1159       syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1160       return AFPERR_PARAM;
1161     }
1162 }
1163
1164 /* resolve a file id */
1165 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1166     AFPObj      *obj;
1167     char        *ibuf, *rbuf;
1168     int         ibuflen, *rbuflen;
1169 {
1170     struct stat         st;
1171     struct vol          *vol;
1172     struct dir          *dir;
1173     char                *upath;
1174     int                 err, buflen;
1175     cnid_t              id;
1176     u_int16_t           vid, bitmap;
1177     
1178
1179     *rbuflen = 0;
1180     ibuf += 2;
1181
1182     memcpy(&vid, ibuf, sizeof(vid));
1183     ibuf += sizeof(vid);
1184
1185     if (( vol = getvolbyvid( vid )) == NULL ) {
1186         return( AFPERR_PARAM);
1187     }
1188
1189     memcpy(&id, ibuf, sizeof( id ));
1190     ibuf += sizeof(id);
1191
1192     if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1193       return AFPERR_BADID;
1194     }
1195
1196     if (( dir = dirsearch( vol, id )) == NULL ) {
1197       return( AFPERR_PARAM );
1198     }
1199
1200     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1201       switch (errno) {
1202       case EACCES:
1203       case EPERM:
1204         return AFPERR_ACCESS;
1205       case ENOENT:
1206         return AFPERR_NOID;
1207       default:
1208         return AFPERR_PARAM;
1209       }
1210     }
1211
1212     /* directories are bad */
1213     if (S_ISDIR(st.st_mode))
1214       return AFPERR_BADTYPE;
1215
1216     memcpy(&bitmap, ibuf, sizeof(bitmap));
1217     bitmap = ntohs( bitmap );
1218
1219     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1220                            rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1221       return err;
1222
1223     *rbuflen = buflen + sizeof(bitmap);
1224     memcpy(rbuf, ibuf, sizeof(bitmap));
1225     return AFP_OK;
1226 }
1227
1228 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1229     AFPObj      *obj;
1230     char        *ibuf, *rbuf;
1231     int         ibuflen, *rbuflen;
1232 {
1233     struct stat         st;
1234     struct vol          *vol;
1235     struct dir          *dir;
1236     char                *upath;
1237     int                 err;
1238     cnid_t              id;
1239     u_short             vid;
1240     
1241
1242     *rbuflen = 0;
1243     ibuf += 2;
1244
1245     memcpy(&vid, ibuf, sizeof(vid));
1246     ibuf += sizeof(vid);
1247
1248     if (( vol = getvolbyvid( vid )) == NULL ) {
1249         return( AFPERR_PARAM);
1250     }
1251
1252     if (vol->v_flags & AFPVOL_RO)
1253         return AFPERR_VLOCK;
1254
1255     memcpy(&id, ibuf, sizeof( id ));
1256     ibuf += sizeof(id);
1257
1258     if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1259       return AFPERR_NOID;
1260     }
1261
1262     if (( dir = dirsearch( vol, id )) == NULL ) {
1263       return( AFPERR_PARAM );
1264     }
1265
1266     err = AFP_OK;
1267     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1268       switch (errno) {
1269       case EACCES:
1270       case EPERM:
1271         return AFPERR_ACCESS;
1272       case ENOENT:
1273         /* still try to delete the id */
1274         err = AFPERR_NOOBJ;
1275         break;
1276       default:
1277         return AFPERR_PARAM;
1278       }
1279     }
1280
1281     /* directories are bad */
1282     if (S_ISDIR(st.st_mode))
1283       return AFPERR_BADTYPE;
1284
1285     if (cnid_delete(vol->v_db, id)) {
1286       switch (errno) {
1287       case EROFS:
1288         return AFPERR_VLOCK;
1289       case EPERM:
1290       case EACCES:
1291         return AFPERR_ACCESS;
1292       default:
1293         return AFPERR_PARAM;
1294       }
1295     }
1296
1297     return err;
1298 }
1299 #endif
1300
1301 #define APPLETEMP ".AppleTempXXXXXX"
1302 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1303     AFPObj      *obj;
1304     char        *ibuf, *rbuf;
1305     int         ibuflen, *rbuflen;
1306 {
1307     struct stat         srcst, destst;
1308     struct vol          *vol;
1309     struct dir          *dir, *sdir;
1310     char                *spath, temp[17], *path, *p;
1311     char                *supath, *upath;
1312     int                 err;
1313 #if AD_VERSION > AD_VERSION1
1314     int                 slen, dlen;
1315 #endif
1316     cnid_t              sid, did;
1317     u_int16_t           vid;
1318     
1319
1320     *rbuflen = 0;
1321     ibuf += 2;
1322
1323     memcpy(&vid, ibuf, sizeof(vid));
1324     ibuf += sizeof(vid);
1325
1326     if (( vol = getvolbyvid( vid )) == NULL ) {
1327         return( AFPERR_PARAM);
1328     }
1329
1330     if (vol->v_flags & AFPVOL_RO)
1331         return AFPERR_VLOCK;
1332
1333     /* source and destination dids */
1334     memcpy(&sid, ibuf, sizeof(sid));
1335     ibuf += sizeof(sid);
1336     memcpy(&did, ibuf, sizeof(did));
1337     ibuf += sizeof(did);
1338
1339     /* source file */
1340     if ((dir = dirsearch( vol, sid )) == NULL ) {
1341         return( AFPERR_PARAM );
1342     }
1343
1344     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1345         return( AFPERR_PARAM );
1346     }
1347
1348     if ( *path == '\0' ) {
1349         return( AFPERR_BADTYPE );
1350     }
1351
1352     upath = mtoupath(vol, path);
1353     if (stat(upath, &srcst) < 0) {
1354       switch (errno) {
1355       case ENOENT:
1356         return AFPERR_NOID;
1357       case EPERM:
1358       case EACCES:
1359         return AFPERR_ACCESS;
1360       default:
1361         return AFPERR_PARAM;
1362       }
1363     }
1364
1365     /* save some stuff */
1366     sdir = curdir;
1367     spath = obj->oldtmp;
1368     supath = obj->newtmp;
1369     strcpy(spath, path);
1370     strcpy(supath, upath); /* this is for the cnid changing */
1371     p = ctoupath( vol, sdir, spath);
1372
1373     /* look for the source cnid. if it doesn't exist, don't worry about
1374      * it. */
1375 #if AD_VERSION > AD_VERSION1
1376     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath, 
1377                       slen = strlen(supath));
1378 #endif
1379
1380     if (( dir = dirsearch( vol, did )) == NULL ) {
1381         return( AFPERR_PARAM );
1382     }
1383
1384     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1385         return( AFPERR_PARAM );
1386     }
1387
1388     if ( *path == '\0' ) {
1389         return( AFPERR_BADTYPE );
1390     }
1391
1392     /* FPExchangeFiles is the only call that can return the SameObj
1393      * error */
1394     if ((curdir == sdir) && strcmp(spath, path) == 0)
1395       return AFPERR_SAMEOBJ;
1396
1397     upath = mtoupath(vol, path);
1398     if (stat(upath, &destst) < 0) {
1399       switch (errno) {
1400       case ENOENT:
1401         return AFPERR_NOID;
1402       case EPERM:
1403       case EACCES:
1404         return AFPERR_ACCESS;
1405       default:
1406         return AFPERR_PARAM;
1407       }
1408     }
1409
1410 #if AD_VERSION > AD_VERSION1
1411     /* look for destination id. */
1412     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath, 
1413                       dlen = strlen(upath));
1414 #endif
1415
1416     /* construct a temp name. 
1417      * NOTE: the temp file will be in the dest file's directory. it
1418      * will also be inaccessible from AFP. */
1419     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1420     if (!mktemp(temp))
1421       return AFPERR_MISC;
1422
1423     /* now, quickly rename the file. we error if we can't. */
1424     if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1425       goto err_exchangefile;
1426     of_rename(vol, sdir, spath, curdir, temp);
1427
1428     /* rename destination to source */
1429     if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0) 
1430       goto err_src_to_tmp;
1431     of_rename(vol, curdir, path, sdir, spath);
1432
1433     /* rename temp to destination */
1434     if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0) 
1435       goto err_dest_to_src;
1436     of_rename(vol, curdir, temp, curdir, path);
1437     
1438 #if AD_VERSION > AD_VERSION1
1439     /* id's need switching. src -> dest and dest -> src. */
1440     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did, 
1441                             upath, dlen) < 0)) {
1442       switch (errno) {
1443       case EPERM:
1444       case EACCES:
1445         err = AFPERR_ACCESS;
1446       default:
1447         err = AFPERR_PARAM;
1448       }
1449       goto err_temp_to_dest;
1450     }
1451
1452     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1453                             supath, slen) < 0)) {
1454       switch (errno) {
1455       case EPERM:
1456       case EACCES:
1457         err = AFPERR_ACCESS;
1458       default:
1459         err = AFPERR_PARAM;
1460       }
1461
1462       if (sid)
1463         cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1464       goto err_temp_to_dest;
1465     }
1466 #endif
1467     return AFP_OK;
1468
1469
1470     /* all this stuff is so that we can unwind a failed operation 
1471      * properly. */
1472 err_temp_to_dest:
1473     /* rename dest to temp */
1474     renamefile(upath, temp, temp, vol_noadouble(vol));
1475     of_rename(vol, curdir, upath, curdir, temp);
1476
1477 err_dest_to_src:
1478     /* rename source back to dest */
1479     renamefile(p, upath, path, vol_noadouble(vol));
1480     of_rename(vol, sdir, spath, curdir, path);
1481
1482 err_src_to_tmp:
1483     /* rename temp back to source */
1484     renamefile(temp, p, spath, vol_noadouble(vol));
1485     of_rename(vol, curdir, temp, sdir, spath);
1486
1487 err_exchangefile:
1488     return err;
1489 }