]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
AFP3 with UTF8 ckeck name parameter is not too big.
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.90 2003-04-20 06:13:41 didg 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 <stdio.h>
13 #include <stdlib.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif /* HAVE_UNISTD_H */
17
18 /* STDC check */
19 #if STDC_HEADERS
20 #include <string.h>
21 #else /* STDC_HEADERS */
22 #ifndef HAVE_STRCHR
23 #define strchr index
24 #define strrchr index
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
27 #ifndef HAVE_MEMCPY
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
32
33 #include <utime.h>
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif /* HAVE_FCNTL_H */
37 #include <dirent.h>
38 #include <sys/mman.h>
39 #include <errno.h>
40
41 #include <atalk/logger.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/param.h>
45 #include <sys/stat.h>
46
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
51 #ifdef CNID_DB
52 #include <atalk/cnid.h>
53 #endif /* CNID_DB */
54 #include "directory.h"
55 #include "desktop.h"
56 #include "volume.h"
57 #include "fork.h"
58 #include "file.h"
59 #include "filedir.h"
60 #include "globals.h"
61
62 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63  * field         bytes        subfield    bytes
64  * 
65  * files:
66  * ioFlFndrInfo  16      ->       type    4  type field
67  *                             creator    4  creator field
68  *                               flags    2  finder flags:
69  *                                           alias, bundle, etc.
70  *                            location    4  location in window
71  *                              folder    2  window that contains file
72  * 
73  * ioFlXFndrInfo 16      ->     iconID    2  icon id
74  *                              unused    6  reserved 
75  *                              script    1  script system
76  *                              xflags    1  reserved
77  *                           commentID    2  comment id
78  *                           putawayID    4  home directory id
79  */
80
81 const u_char ufinderi[] = {
82                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83                               0, 0, 0, 0, 0, 0, 0, 0,
84                               0, 0, 0, 0, 0, 0, 0, 0,
85                               0, 0, 0, 0, 0, 0, 0, 0
86                           };
87
88 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
90 {
91     struct extmap       *em;
92
93     if (adp) {
94         memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
95     }
96     else {
97         memcpy(data, ufinderi, 32);
98     }
99
100     if ((!adp  || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) 
101                 && (em = getextmap( mpath ))
102     ) {
103         memcpy(data, em->em_type, sizeof( em->em_type ));
104         memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
105     }
106     return data;
107 }
108
109 /* ---------------------
110 */
111 char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8) 
112 {
113     u_int32_t   aint;
114     char        *tp = NULL;
115     char        *src = name;
116     aint = strlen( name );
117
118     if (!utf8) {
119         /* want mac name */
120         if (utf8_encoding()) {
121             /* but name is an utf8 mac name */
122             char *u, *m;
123            
124             /* global static variable... */
125             tp = strdup(name);
126             if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) {
127                aint = 0;
128             }
129             else {
130                 aint = strlen(m);
131                 src = m;
132             }
133             
134         }
135         if (aint > MACFILELEN)
136             aint = MACFILELEN;
137         *data++ = aint;
138     }
139     else {
140         u_int16_t temp;
141
142         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
143            aint = 255;
144
145         utf8 = htonl(utf8);
146         memcpy(data, &utf8, sizeof(utf8));
147         data += sizeof(utf8);
148         
149         temp = htons(aint);
150         memcpy(data, &temp, sizeof(temp));
151         data += sizeof(temp);
152     }
153
154     memcpy( data, src, aint );
155     data += aint;
156     if (tp) {
157         strcpy(name, tp);
158         free(tp);
159     }
160     return data;
161 }
162
163 /*
164  * FIXME: PDINFO is UTF8 and doesn't need adp
165 */
166 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR)  |\
167                                   (1 << FILPBIT_CDATE) |\
168                                   (1 << FILPBIT_MDATE) |\
169                                   (1 << FILPBIT_BDATE) |\
170                                   (1 << FILPBIT_FINFO) |\
171                                   (1 << FILPBIT_RFLEN) |\
172                                   (1 << FILPBIT_EXTRFLEN) |\
173                                   (1 << FILPBIT_PDINFO)))
174
175 /* -------------------------- */
176 u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
177              const cnid_t did, const char *upath, const int len) 
178 {
179 u_int32_t aint = 0;
180
181 #ifdef CNID_DB
182
183     aint = cnid_add(vol->v_db, st, did, upath, len, aint);
184     /* Throw errors if cnid_add fails. */
185     if (aint == CNID_INVALID) {
186         switch (errno) {
187         case CNID_ERR_CLOSE: /* the db is closed */
188             break;
189         case CNID_ERR_PARAM:
190             LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
191             afp_errno = AFPERR_PARAM;
192             return CNID_INVALID;
193         case CNID_ERR_PATH:
194             afp_errno = AFPERR_PARAM;
195             return CNID_INVALID;
196         default:
197             afp_errno = AFPERR_MISC;
198             return CNID_INVALID;
199         }
200     }
201 #endif /* CNID_DB */
202
203     if (aint == 0) {
204         /*
205          * First thing:  DID and FNUMs are
206          * in the same space for purposes of enumerate (and several
207          * other wierd places).  While we consider this Apple's bug,
208          * this is the work-around:  In order to maintain constant and
209          * unique DIDs and FNUMs, we monotonically generate the DIDs
210          * during the session, and derive the FNUMs from the filesystem.
211          * Since the DIDs are small, we insure that the FNUMs are fairly
212          * large by setting thier high bits to the device number.
213          *
214          * AFS already does something very similar to this for the
215          * inode number, so we don't repeat the procedure.
216          *
217          * new algorithm:
218          * due to complaints over did's being non-persistent,
219          * here's the current hack to provide semi-persistent
220          * did's:
221          *      1) we reserve the first bit for file ids.
222          *      2) the next 7 bits are for the device.
223          *      3) the remaining 24 bits are for the inode.
224          *
225          * both the inode and device information are actually hashes
226          * that are then truncated to the requisite bit length.
227          *
228          * it should be okay to use lstat to deal with symlinks.
229          */
230 #ifdef USE_LASTDID
231         if ( S_ISDIR(st->st_mode)) {
232             aint = htonl( vol->v_lastdid++ );
233         }
234         else
235         {
236             aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
237         }
238 #else /* USE_LASTDID */
239         {
240             struct stat lst;
241             const struct stat *lstp;
242
243             lstp = lstat(upath, &lst) < 0 ? st : &lst;
244             aint = htonl(CNID(lstp, 1));
245         }
246 #endif /* USE_LASTDID */
247     }
248     return aint;
249 }
250              
251 /* -------------------------- */
252 int getmetadata(struct vol *vol,
253                  u_int16_t bitmap,
254                  struct path *path, struct dir *dir, 
255                  char *buf, int *buflen, struct adouble *adp, int attrbits )
256 {
257     char                *data, *l_nameoff = NULL, *upath;
258     char                *utf_nameoff = NULL;
259     int                 bit = 0;
260     u_int32_t           aint;
261     u_int16_t           ashort;
262     u_char              achar, fdType[4];
263     u_int32_t           utf8 = 0;
264     struct stat         *st;
265 #ifdef DEBUG
266     LOG(log_info, logtype_afpd, "begin getmetadata:");
267 #endif /* DEBUG */
268
269     upath = path->u_name;
270     st = &path->st;
271
272     data = buf;
273     while ( bitmap != 0 ) {
274         while (( bitmap & 1 ) == 0 ) {
275             bitmap = bitmap>>1;
276             bit++;
277         }
278
279         switch ( bit ) {
280         case FILPBIT_ATTR :
281             if ( adp ) {
282                 ad_getattr(adp, &ashort);
283             } else if (*upath == '.') {
284                 ashort = htons(ATTRBIT_INVISIBLE);
285             } else
286                 ashort = 0;
287 #if 0
288             /* FIXME do we want a visual clue if the file is read only
289              */
290             struct maccess      ma;
291             accessmode( ".", &ma, dir , NULL);
292             if ((ma.ma_user & AR_UWRITE)) {
293                 accessmode( upath, &ma, dir , st);
294                 if (!(ma.ma_user & AR_UWRITE)) {
295                         attrbits |= ATTRBIT_NOWRITE;
296                 }
297             }
298 #endif
299             if (attrbits)
300                 ashort = htons(ntohs(ashort) | attrbits);
301             memcpy(data, &ashort, sizeof( ashort ));
302             data += sizeof( ashort );
303             break;
304
305         case FILPBIT_PDID :
306             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
307             data += sizeof( u_int32_t );
308             break;
309
310         case FILPBIT_CDATE :
311             if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
312                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
313             memcpy(data, &aint, sizeof( aint ));
314             data += sizeof( aint );
315             break;
316
317         case FILPBIT_MDATE :
318             if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
319                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
320                    aint = AD_DATE_FROM_UNIX(st->st_mtime);
321                 }
322             } else {
323                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324             }
325             memcpy(data, &aint, sizeof( int ));
326             data += sizeof( int );
327             break;
328
329         case FILPBIT_BDATE :
330             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
331                 aint = AD_DATE_START;
332             memcpy(data, &aint, sizeof( int ));
333             data += sizeof( int );
334             break;
335
336         case FILPBIT_FINFO :
337             get_finderinfo(path->m_name, adp, (char *)data);
338             if (!adp) {
339                 if (*upath == '.') { /* make it invisible */
340                     ashort = htons(FINDERINFO_INVISIBLE);
341                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
342                 }
343             }
344             data += 32;
345             break;
346
347         case FILPBIT_LNAME :
348             l_nameoff = data;
349             data += sizeof( u_int16_t );
350             break;
351
352         case FILPBIT_SNAME :
353             memset(data, 0, sizeof(u_int16_t));
354             data += sizeof( u_int16_t );
355             break;
356
357         case FILPBIT_FNUM :
358             aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
359             if (aint == 0)
360                 return afp_errno;
361             memcpy(data, &aint, sizeof( aint ));
362             data += sizeof( aint );
363             break;
364
365         case FILPBIT_DFLEN :
366             if  (st->st_size > 0xffffffff)
367                aint = 0xffffffff;
368             else
369                aint = htonl( st->st_size );
370             memcpy(data, &aint, sizeof( aint ));
371             data += sizeof( aint );
372             break;
373
374         case FILPBIT_RFLEN :
375             if ( adp ) {
376                 if (adp->ad_rlen > 0xffffffff)
377                     aint = 0xffffffff;
378                 else
379                     aint = htonl( adp->ad_rlen);
380             } else {
381                 aint = 0;
382             }
383             memcpy(data, &aint, sizeof( aint ));
384             data += sizeof( aint );
385             break;
386
387             /* Current client needs ProDOS info block for this file.
388                Use simple heuristic and let the Mac "type" string tell
389                us what the PD file code should be.  Everything gets a
390                subtype of 0x0000 unless the original value was hashed
391                to "pXYZ" when we created it.  See IA, Ver 2.
392                <shirsch@adelphia.net> */
393         case FILPBIT_PDINFO :
394             if (afp_version >= 30) { /* UTF8 name */
395                 utf8 = kTextEncodingUTF8;
396                 utf_nameoff = data;
397                 data += sizeof( u_int16_t );
398                 aint = 0;
399                 memcpy(data, &aint, sizeof( aint ));
400                 data += sizeof( aint );
401             }
402             else {
403                 if ( adp ) {
404                     memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
405
406                     if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
407                         achar = '\x04';
408                         ashort = 0x0000;
409                     }
410                     else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
411                         achar = '\xff';
412                         ashort = 0x0000;
413                     }
414                     else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
415                         achar = '\xb3';
416                         ashort = 0x0000;
417                     }
418                     else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
419                         achar = '\x00';
420                         ashort = 0x0000;
421                     }
422                     else if ( fdType[0] == 'p' ) {
423                         achar = fdType[1];
424                         ashort = (fdType[2] * 256) + fdType[3];
425                     }
426                     else {
427                         achar = '\x00';
428                         ashort = 0x0000;
429                     }
430                 }
431                 else {
432                     achar = '\x00';
433                     ashort = 0x0000;
434                 }
435
436                 *data++ = achar;
437                 *data++ = 0;
438                 memcpy(data, &ashort, sizeof( ashort ));
439                 data += sizeof( ashort );
440                 memset(data, 0, sizeof( ashort ));
441                 data += sizeof( ashort );
442             }
443             break;
444         case FILPBIT_EXTDFLEN:
445             aint = htonl(st->st_size >> 32);
446             memcpy(data, &aint, sizeof( aint ));
447             data += sizeof( aint );
448             aint = htonl(st->st_size);
449             memcpy(data, &aint, sizeof( aint ));
450             data += sizeof( aint );
451             break;
452         case FILPBIT_EXTRFLEN:
453             aint = 0;
454             if (adp) 
455                 aint = htonl(adp->ad_rlen >> 32);
456             memcpy(data, &aint, sizeof( aint ));
457             data += sizeof( aint );
458             if (adp) 
459                 aint = htonl(adp->ad_rlen);
460             memcpy(data, &aint, sizeof( aint ));
461             data += sizeof( aint );
462             break;
463         default :
464             return( AFPERR_BITMAP );
465         }
466         bitmap = bitmap>>1;
467         bit++;
468     }
469     if ( l_nameoff ) {
470         ashort = htons( data - buf );
471         memcpy(l_nameoff, &ashort, sizeof( ashort ));
472         data = set_name(vol, data, path->m_name, 0);
473     }
474     if ( utf_nameoff ) {
475         ashort = htons( data - buf );
476         memcpy(utf_nameoff, &ashort, sizeof( ashort ));
477         data = set_name(vol, data, path->m_name, utf8);
478     }
479     *buflen = data - buf;
480     return (AFP_OK);
481 }
482                 
483 /* ----------------------- */
484 int getfilparams(struct vol *vol,
485                  u_int16_t bitmap,
486                  struct path *path, struct dir *dir, 
487                  char *buf, int *buflen )
488 {
489     struct adouble      ad, *adp;
490     struct ofork        *of;
491     char                    *upath;
492     u_int16_t           attrbits = 0;
493     int                 opened = 0;
494     int rc;    
495
496 #ifdef DEBUG
497     LOG(log_info, logtype_default, "begin getfilparams:");
498 #endif /* DEBUG */
499
500     opened = PARAM_NEED_ADP(bitmap);
501     adp = NULL;
502     if (opened) {
503         upath = path->u_name;
504         if ((of = of_findname(path))) {
505             adp = of->of_ad;
506             attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
507             attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
508         } else {
509             memset(&ad, 0, sizeof(ad));
510             adp = &ad;
511         }
512
513         if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
514              adp = NULL;
515         }
516         else {
517             /* FIXME 
518                we need to check if the file is open by another process.
519                it's slow so we only do it if we have to:
520                - bitmap is requested.
521                - we don't already have the answer!
522             */
523             if ((bitmap & (1 << FILPBIT_ATTR))) {
524                  if (!(attrbits & ATTRBIT_ROPEN)) {
525                  }
526                  if (!(attrbits & ATTRBIT_DOPEN)) {
527                  }
528             }
529         }
530     }
531     rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
532     if ( adp ) {
533         ad_close( adp, ADFLAGS_HF );
534     }
535 #ifdef DEBUG
536     LOG(log_info, logtype_afpd, "end getfilparams:");
537 #endif /* DEBUG */
538
539     return( rc );
540 }
541
542 /* ----------------------------- */
543 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
544 AFPObj      *obj;
545 char    *ibuf, *rbuf;
546 int             ibuflen, *rbuflen;
547 {
548     struct adouble      ad, *adp;
549     struct vol          *vol;
550     struct dir          *dir;
551     struct ofork        *of = NULL;
552     char                *path, *upath;
553     int                 creatf, did, openf, retvalue = AFP_OK;
554     u_int16_t           vid;
555     int                 ret;
556     struct path         *s_path;
557     
558 #ifdef DEBUG
559     LOG(log_info, logtype_afpd, "begin afp_createfile:");
560 #endif /* DEBUG */
561
562     *rbuflen = 0;
563     ibuf++;
564     creatf = (unsigned char) *ibuf++;
565
566     memcpy(&vid, ibuf, sizeof( vid ));
567     ibuf += sizeof( vid );
568
569     if (NULL == ( vol = getvolbyvid( vid )) ) {
570         return( AFPERR_PARAM );
571     }
572
573     if (vol->v_flags & AFPVOL_RO)
574         return AFPERR_VLOCK;
575
576     memcpy(&did, ibuf, sizeof( did));
577     ibuf += sizeof( did );
578
579     if (NULL == ( dir = dirlookup( vol, did )) ) {
580         return afp_errno;
581     }
582
583     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
584         return get_afp_errno(AFPERR_PARAM);
585     }
586
587     if ( *s_path->m_name == '\0' ) {
588         return( AFPERR_BADTYPE );
589     }
590
591     upath = s_path->u_name;
592     if (0 != (ret = check_name(vol, upath))) 
593        return  ret;
594     
595     /* if upath is deleted we already in trouble anyway */
596     if ((of = of_findname(s_path))) {
597         adp = of->of_ad;
598     } else {
599         memset(&ad, 0, sizeof(ad));
600         adp = &ad;
601     }
602     if ( creatf) {
603         /* on a hard create, fail if file exists and is open */
604         if (of)
605             return AFPERR_BUSY;
606         openf = O_RDWR|O_CREAT|O_TRUNC;
607     } else {
608         /* on a soft create, if the file is open then ad_open won't fail
609            because open syscall is not called
610         */
611         if (of) {
612                 return AFPERR_EXIST;
613         }
614         openf = O_RDWR|O_CREAT|O_EXCL;
615     }
616
617     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
618                   openf, 0666, adp) < 0 ) {
619         switch ( errno ) {
620         case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
621             return ( AFPERR_NOOBJ );
622         case EEXIST :
623             return( AFPERR_EXIST );
624         case EACCES :
625             return( AFPERR_ACCESS );
626         default :
627             return( AFPERR_PARAM );
628         }
629     }
630     if ( ad_hfileno( adp ) == -1 ) {
631          /* on noadouble volumes, just creating the data fork is ok */
632          if (vol_noadouble(vol)) {
633              ad_close( adp, ADFLAGS_DF );
634              goto createfile_done;
635          }
636          /* FIXME with hard create on an existing file, we already
637           * corrupted the data file.
638           */
639          netatalk_unlink( upath );
640          ad_close( adp, ADFLAGS_DF );
641          return AFPERR_ACCESS;
642     }
643
644     path = s_path->m_name;
645     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
646     memcpy(ad_entry( adp, ADEID_NAME ), path,
647            ad_getentrylen( adp, ADEID_NAME ));
648     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
649     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
650
651 createfile_done:
652     curdir->offcnt++;
653
654 #ifdef DROPKLUDGE
655     if (vol->v_flags & AFPVOL_DROPBOX) {
656         retvalue = matchfile2dirperms(upath, vol, did);
657     }
658 #endif /* DROPKLUDGE */
659
660     setvoltime(obj, vol );
661
662 #ifdef DEBUG
663     LOG(log_info, logtype_afpd, "end afp_createfile");
664 #endif /* DEBUG */
665
666     return (retvalue);
667 }
668
669 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
670 AFPObj      *obj;
671 char    *ibuf, *rbuf;
672 int             ibuflen, *rbuflen;
673 {
674     struct vol  *vol;
675     struct dir  *dir;
676     struct path *s_path;
677     int         did, rc;
678     u_int16_t   vid, bitmap;
679
680 #ifdef DEBUG
681     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
682 #endif /* DEBUG */
683
684     *rbuflen = 0;
685     ibuf += 2;
686
687     memcpy(&vid, ibuf, sizeof( vid ));
688     ibuf += sizeof( vid );
689     if (NULL == ( vol = getvolbyvid( vid )) ) {
690         return( AFPERR_PARAM );
691     }
692
693     if (vol->v_flags & AFPVOL_RO)
694         return AFPERR_VLOCK;
695
696     memcpy(&did, ibuf, sizeof( did ));
697     ibuf += sizeof( did );
698     if (NULL == ( dir = dirlookup( vol, did )) ) {
699         return afp_errno; /* was AFPERR_NOOBJ */
700     }
701
702     memcpy(&bitmap, ibuf, sizeof( bitmap ));
703     bitmap = ntohs( bitmap );
704     ibuf += sizeof( bitmap );
705
706     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
707         return get_afp_errno(AFPERR_PARAM);
708     }
709
710     if (path_isadir(s_path)) {
711         return( AFPERR_BADTYPE ); /* it's a directory */
712     }
713
714     if ((u_long)ibuf & 1 ) {
715         ibuf++;
716     }
717
718     if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
719         setvoltime(obj, vol );
720     }
721
722 #ifdef DEBUG
723     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
724 #endif /* DEBUG */
725
726     return( rc );
727 }
728
729 /*
730  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
731  *
732 */
733 extern struct path Cur_Path;
734
735 int setfilparams(struct vol *vol,
736                  struct path *path, u_int16_t bitmap, char *buf )
737 {
738     struct adouble      ad, *adp;
739     struct ofork        *of;
740     struct extmap       *em;
741     int                 bit = 0, isad = 1, err = AFP_OK;
742     char                *upath;
743     u_char              achar, *fdType, xyy[4];
744     u_int16_t           ashort, bshort;
745     u_int32_t           aint;
746     struct utimbuf      ut;
747
748     int                 change_mdate = 0;
749     int                 change_parent_mdate = 0;
750     int                 newdate = 0;
751     struct timeval      tv;
752
753
754 #ifdef DEBUG
755     LOG(log_info, logtype_afpd, "begin setfilparams:");
756 #endif /* DEBUG */
757
758     upath = path->u_name;
759     if ((of = of_findname(path))) {
760         adp = of->of_ad;
761     } else {
762         memset(&ad, 0, sizeof(ad));
763         adp = &ad;
764     }
765
766     if (check_access(upath, OPENACC_WR ) < 0) {
767         return AFPERR_ACCESS;
768     }
769
770     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
771                  O_RDWR|O_CREAT, 0666, adp) < 0) {
772         /* for some things, we don't need an adouble header */
773         if (bitmap & ~(1<<FILPBIT_MDATE)) {
774             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
775         }
776         isad = 0;
777     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
778         ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
779         memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
780                ad_getentrylen( adp, ADEID_NAME ));
781     }
782
783     while ( bitmap != 0 ) {
784         while (( bitmap & 1 ) == 0 ) {
785             bitmap = bitmap>>1;
786             bit++;
787         }
788
789         switch(  bit ) {
790         case FILPBIT_ATTR :
791             change_mdate = 1;
792             memcpy(&ashort, buf, sizeof( ashort ));
793             ad_getattr(adp, &bshort);
794             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
795                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
796             } else {
797                 bshort &= ~ashort;
798             }
799             if ((ashort & htons(ATTRBIT_INVISIBLE)))
800                 change_parent_mdate = 1;
801             ad_setattr(adp, bshort);
802             buf += sizeof( ashort );
803             break;
804
805         case FILPBIT_CDATE :
806             change_mdate = 1;
807             memcpy(&aint, buf, sizeof(aint));
808             ad_setdate(adp, AD_DATE_CREATE, aint);
809             buf += sizeof( aint );
810             break;
811
812         case FILPBIT_MDATE :
813             memcpy(&newdate, buf, sizeof( newdate ));
814             buf += sizeof( newdate );
815             break;
816
817         case FILPBIT_BDATE :
818             change_mdate = 1;
819             memcpy(&aint, buf, sizeof(aint));
820             ad_setdate(adp, AD_DATE_BACKUP, aint);
821             buf += sizeof( aint );
822             break;
823
824         case FILPBIT_FINFO :
825             change_mdate = 1;
826
827             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
828                     && ( 
829                      ((em = getextmap( path->m_name )) &&
830                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
831                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
832                      || ((em = getdefextmap()) &&
833                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
834                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
835             )) {
836                 memcpy(buf, ufinderi, 8 );
837             }
838
839             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
840             buf += 32;
841             break;
842
843             /* Client needs to set the ProDOS file info for this file.
844                Use a defined string for TEXT to support crlf
845                translations and convert all else into pXYY per Inside
846                Appletalk.  Always set the creator as "pdos".  Changes
847                from original by Marsha Jackson. */
848         case FILPBIT_PDINFO :
849             if (afp_version < 30) { /* else it's UTF8 name */
850                 achar = *buf;
851                 buf += 2;
852                 /* Keep special case to support crlf translations */
853                 if ((unsigned int) achar == 0x04) {
854                     fdType = (u_char *)"TEXT";
855                     buf += 2;
856                 } else {
857                     xyy[0] = ( u_char ) 'p';
858                     xyy[1] = achar;
859                     xyy[3] = *buf++;
860                     xyy[2] = *buf++;
861                     fdType = xyy;
862                 }
863                 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
864                 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
865                 break;
866             }
867             /* fallthrough */
868         default :
869             err = AFPERR_BITMAP;
870             goto setfilparam_done;
871         }
872
873         bitmap = bitmap>>1;
874         bit++;
875     }
876
877 setfilparam_done:
878     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
879        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
880     }
881     if (newdate) {
882        if (isad)
883           ad_setdate(adp, AD_DATE_MODIFY, newdate);
884        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
885        utime(upath, &ut);
886     }
887
888     if (isad) {
889         ad_flush( adp, ADFLAGS_HF );
890         ad_close( adp, ADFLAGS_HF );
891
892     }
893
894     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
895         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
896         bitmap = 1<<FILPBIT_MDATE;
897         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
898     }
899
900 #ifdef DEBUG
901     LOG(log_info, logtype_afpd, "end setfilparams:");
902 #endif /* DEBUG */
903     return err;
904 }
905
906 /*
907  * renamefile and copyfile take the old and new unix pathnames
908  * and the new mac name.
909  *
910  * src         the source path 
911  * dst         the dest filename in current dir
912  * newname     the dest mac name
913  * adp         adouble struct of src file, if open, or & zeroed one
914  *
915  */
916 int renamefile(src, dst, newname, noadouble, adp )
917 char    *src, *dst, *newname;
918 const int         noadouble;
919 struct adouble    *adp;
920 {
921     char        adsrc[ MAXPATHLEN + 1];
922     int         len;
923     int         rc;
924
925 #ifdef DEBUG
926     LOG(log_info, logtype_afpd, "begin renamefile:");
927 #endif /* DEBUG */
928
929     if ( unix_rename( src, dst ) < 0 ) {
930         switch ( errno ) {
931         case ENOENT :
932             return( AFPERR_NOOBJ );
933         case EPERM:
934         case EACCES :
935             return( AFPERR_ACCESS );
936         case EROFS:
937             return AFPERR_VLOCK;
938         case EXDEV :                    /* Cross device move -- try copy */
939            /* NOTE: with open file it's an error because after the copy we will 
940             * get two files, it's fixable for our process (eg reopen the new file, get the
941             * locks, and so on. But it doesn't solve the case with a second process
942             */
943             if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
944                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
945                 return AFPERR_OLOCK; /* little lie */
946             }
947             if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
948                 /* on error copyfile delete dest */
949                 return( rc );
950             }
951             return deletefile(NULL, src, 0);
952         default :
953             return( AFPERR_PARAM );
954         }
955     }
956
957     strcpy( adsrc, ad_path( src, 0 ));
958
959     if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
960         struct stat st;
961         int err;
962         
963         err = errno;        
964         if (errno == ENOENT) {
965             struct adouble    ad;
966
967             if (stat(adsrc, &st)) /* source has no ressource fork, */
968                 return AFP_OK;
969             
970             /* We are here  because :
971              * -there's no dest folder. 
972              * -there's no .AppleDouble in the dest folder.
973              * if we use the struct adouble passed in parameter it will not
974              * create .AppleDouble if the file is already opened, so we
975              * use a diff one, it's not a pb,ie it's not the same file, yet.
976              */
977             memset(&ad, 0, sizeof(ad));
978             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
979                 ad_close(&ad, ADFLAGS_HF);
980                 if (!unix_rename( adsrc, ad_path( dst, 0 )) ) 
981                    err = 0;
982                 else 
983                    err = errno;
984             }
985             else { /* it's something else, bail out */
986                 err = errno;
987             }
988         }
989         /* try to undo the data fork rename,
990          * we know we are on the same device 
991         */
992         if (err) {
993             unix_rename( dst, src ); 
994             /* return the first error */
995             switch ( err) {
996             case ENOENT :
997                 return AFPERR_NOOBJ;
998             case EPERM:
999             case EACCES :
1000                 return AFPERR_ACCESS ;
1001             case EROFS:
1002                 return AFPERR_VLOCK;
1003             default :
1004                 return AFPERR_PARAM ;
1005             }
1006         }
1007     }
1008
1009     /* don't care if we can't open the newly renamed ressource fork
1010      */
1011     if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1012         len = strlen( newname );
1013         ad_setentrylen( adp, ADEID_NAME, len );
1014         memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1015         ad_flush( adp, ADFLAGS_HF );
1016         ad_close( adp, ADFLAGS_HF );
1017     }
1018 #ifdef DEBUG
1019     LOG(log_info, logtype_afpd, "end renamefile:");
1020 #endif /* DEBUG */
1021
1022     return( AFP_OK );
1023 }
1024
1025 int copy_path_name(char *newname, char *ibuf)
1026 {
1027 char        type = *ibuf;
1028 size_t      plen = 0;
1029 u_int16_t   len16;
1030 u_int32_t   hint;
1031
1032     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1033         return -1;
1034     }
1035     ibuf++;
1036     switch (type) {
1037     case 2:
1038         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1039             strncpy( newname, ibuf, plen );
1040             newname[ plen ] = '\0';
1041             if (strlen(newname) != plen) {
1042                 /* there's \0 in newname, e.g. it's a pathname not
1043                  * only a filename. 
1044                 */
1045                 return -1;
1046             }
1047         }
1048         break;
1049     case 3:
1050         memcpy(&hint, ibuf, sizeof(hint));
1051         ibuf += sizeof(hint);
1052            
1053         memcpy(&len16, ibuf, sizeof(len16));
1054         ibuf += sizeof(len16);
1055         plen = ntohs(len16);
1056         
1057         if (plen) {
1058             if (plen > AFPOBJ_TMPSIZ) {
1059                 return -1;
1060             }
1061             strncpy( newname, ibuf, plen );
1062             newname[ plen ] = '\0';
1063             if (strlen(newname) != plen) {
1064                 return -1;
1065             }
1066         }
1067         break;
1068     }
1069     return plen;
1070 }
1071
1072 /* -----------------------------------
1073 */
1074 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1075 AFPObj      *obj;
1076 char    *ibuf, *rbuf;
1077 int             ibuflen, *rbuflen;
1078 {
1079     struct vol  *vol;
1080     struct dir  *dir;
1081     char        *newname, *p, *upath;
1082     struct path *s_path;
1083     u_int32_t   sdid, ddid;
1084     int         err, retvalue = AFP_OK;
1085     u_int16_t   svid, dvid;
1086
1087 #ifdef DEBUG
1088     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1089 #endif /* DEBUG */
1090
1091     *rbuflen = 0;
1092     ibuf += 2;
1093
1094     memcpy(&svid, ibuf, sizeof( svid ));
1095     ibuf += sizeof( svid );
1096     if (NULL == ( vol = getvolbyvid( svid )) ) {
1097         return( AFPERR_PARAM );
1098     }
1099
1100     memcpy(&sdid, ibuf, sizeof( sdid ));
1101     ibuf += sizeof( sdid );
1102     if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1103         return afp_errno;
1104     }
1105
1106     memcpy(&dvid, ibuf, sizeof( dvid ));
1107     ibuf += sizeof( dvid );
1108     memcpy(&ddid, ibuf, sizeof( ddid ));
1109     ibuf += sizeof( ddid );
1110
1111     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1112         return get_afp_errno(AFPERR_PARAM);
1113     }
1114     if ( path_isadir(s_path) ) {
1115         return( AFPERR_BADTYPE );
1116     }
1117
1118     /* don't allow copies when the file is open.
1119      * XXX: the spec only calls for read/deny write access.
1120      *      however, copyfile doesn't have any of that info,
1121      *      and locks need to stay coherent. as a result,
1122      *      we just balk if the file is opened already. */
1123
1124     newname = obj->newtmp;
1125     strcpy( newname, s_path->m_name );
1126
1127     if (of_findname(s_path))
1128         return AFPERR_DENYCONF;
1129
1130     p = ctoupath( vol, curdir, newname );
1131     if (!p) {
1132         return AFPERR_PARAM;
1133     
1134     }
1135 #ifdef FORCE_UIDGID
1136     /* FIXME svid != dvid && dvid's user can't read svid */
1137 #endif
1138     if (NULL == ( vol = getvolbyvid( dvid )) ) {
1139         return( AFPERR_PARAM );
1140     }
1141
1142     if (vol->v_flags & AFPVOL_RO)
1143         return AFPERR_VLOCK;
1144
1145     if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1146         return afp_errno;
1147     }
1148
1149     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1150         return get_afp_errno(AFPERR_NOOBJ); 
1151     }
1152     if ( *s_path->m_name != '\0' ) {
1153         return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1154     }
1155
1156     /* one of the handful of places that knows about the path type */
1157     if (copy_path_name(newname, ibuf) < 0) {
1158         return( AFPERR_PARAM );
1159     }
1160
1161     if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1162         return( AFPERR_PARAM );
1163     }
1164     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1165         return err;
1166     }
1167     curdir->offcnt++;
1168
1169 #ifdef DROPKLUDGE
1170     if (vol->v_flags & AFPVOL_DROPBOX) {
1171         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1172     }
1173 #endif /* DROPKLUDGE */
1174
1175     setvoltime(obj, vol );
1176
1177 #ifdef DEBUG
1178     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1179 #endif /* DEBUG */
1180
1181     return( retvalue );
1182 }
1183
1184
1185 static __inline__ int copy_all(const int dfd, const void *buf,
1186                                size_t buflen)
1187 {
1188     ssize_t cc;
1189
1190 #ifdef DEBUG
1191     LOG(log_info, logtype_afpd, "begin copy_all:");
1192 #endif /* DEBUG */
1193
1194     while (buflen > 0) {
1195         if ((cc = write(dfd, buf, buflen)) < 0) {
1196             switch (errno) {
1197             case EINTR:
1198                 continue;
1199             case EDQUOT:
1200             case EFBIG:
1201             case ENOSPC:
1202                 return AFPERR_DFULL;
1203             case EROFS:
1204                 return AFPERR_VLOCK;
1205             default:
1206                 return AFPERR_PARAM;
1207             }
1208         }
1209         buflen -= cc;
1210     }
1211
1212 #ifdef DEBUG
1213     LOG(log_info, logtype_afpd, "end copy_all:");
1214 #endif /* DEBUG */
1215
1216     return AFP_OK;
1217 }
1218
1219 /* -------------------------- */
1220 static int copy_fd(int dfd, int sfd)
1221 {
1222     ssize_t cc;
1223     int     err = AFP_OK;
1224     char    filebuf[8192];
1225
1226 #ifdef SENDFILE_FLAVOR_LINUX
1227     struct stat         st;
1228
1229     if (fstat(sfd, &st) == 0) {
1230         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1231             switch (errno) {
1232             case EINVAL:  /* there's no guarantee that all fs support sendfile */
1233                 break;
1234             case EDQUOT:
1235             case EFBIG:
1236             case ENOSPC:
1237                 return AFPERR_DFULL;
1238             case EROFS:
1239                 return AFPERR_VLOCK;
1240             default:
1241                 return AFPERR_PARAM;
1242             }
1243         }
1244         else {
1245            return AFP_OK;
1246         }
1247     }
1248 #endif /* SENDFILE_FLAVOR_LINUX */
1249
1250     while (1) {
1251         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1252             if (errno == EINTR)
1253                 continue;
1254             err = AFPERR_PARAM;
1255             break;
1256         }
1257
1258         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1259             break;
1260     }
1261     return err;
1262 }
1263
1264 /* ----------------------------------
1265  * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1266  * because we are doing it elsewhere.
1267  */
1268 int copyfile(src, dst, newname, noadouble )
1269 char    *src, *dst, *newname;
1270 const int   noadouble;
1271 {
1272     struct adouble      ads, add;
1273     int                 len, err = AFP_OK;
1274     int                 adflags;
1275     
1276 #ifdef DEBUG
1277     LOG(log_info, logtype_afpd, "begin copyfile:");
1278 #endif /* DEBUG */
1279
1280     memset(&ads, 0, sizeof(ads));
1281     memset(&add, 0, sizeof(add));
1282     adflags = ADFLAGS_DF;
1283     if (newname) {
1284         adflags |= ADFLAGS_HF;
1285     }
1286
1287     if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1288         switch ( errno ) {
1289         case ENOENT :
1290             return( AFPERR_NOOBJ );
1291         case EACCES :
1292             return( AFPERR_ACCESS );
1293         default :
1294             return( AFPERR_PARAM );
1295         }
1296     }
1297     if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1298         ad_close( &ads, adflags );
1299         if (EEXIST != (err = errno)) {
1300             deletefile(NULL, dst, 0);
1301         }
1302         switch ( err ) {
1303         case EEXIST :
1304             return AFPERR_EXIST;
1305         case ENOENT :
1306             return( AFPERR_NOOBJ );
1307         case EACCES :
1308             return( AFPERR_ACCESS );
1309         case EROFS:
1310             return AFPERR_VLOCK;
1311         default :
1312             return( AFPERR_PARAM );
1313         }
1314     }
1315     if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1316         /* copy the data fork */
1317         err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1318     }
1319
1320     if (newname) {
1321         len = strlen( newname );
1322         ad_setentrylen( &add, ADEID_NAME, len );
1323         memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1324     }
1325
1326     ad_close( &ads, adflags );
1327     ad_flush( &add, adflags );
1328     if (ad_close( &add, adflags ) <0) {
1329        err = errno;
1330     }
1331     if (err != AFP_OK) {
1332         deletefile(NULL, dst, 0);
1333         switch ( err ) {
1334         case ENOENT :
1335             return( AFPERR_NOOBJ );
1336         case EACCES :
1337             return( AFPERR_ACCESS );
1338         default :
1339             return( AFPERR_PARAM );
1340         }
1341     }
1342
1343 #ifdef DEBUG
1344     LOG(log_info, logtype_afpd, "end copyfile:");
1345 #endif /* DEBUG */
1346
1347     return( AFP_OK );
1348 }
1349
1350
1351 /* -----------------------------------
1352    vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1353    checkAttrib:   1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1354
1355    when deletefile is called we don't have lock on it, file is closed (for us)
1356    untrue if called by renamefile
1357    
1358    ad_open always try to open file RDWR first and ad_lock takes care of
1359    WRITE lock on read only file.
1360 */
1361 int deletefile( vol, file, checkAttrib )
1362 struct vol      *vol;
1363 char            *file;
1364 int         checkAttrib;
1365 {
1366     struct adouble      ad;
1367     int                 adflags, err = AFP_OK;
1368
1369 #ifdef DEBUG
1370     LOG(log_info, logtype_afpd, "begin deletefile:");
1371 #endif /* DEBUG */
1372
1373     /* try to open both forks at once */
1374     adflags = ADFLAGS_DF|ADFLAGS_HF;
1375     while(1) {
1376         memset(&ad, 0, sizeof(ad));
1377         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1378             switch (errno) {
1379             case ENOENT:
1380                 if (adflags == ADFLAGS_DF)
1381                     return AFPERR_NOOBJ;
1382                    
1383                 /* that failed. now try to open just the data fork */
1384                 adflags = ADFLAGS_DF;
1385                 continue;
1386
1387             case EACCES:
1388                 return AFPERR_ACCESS;
1389             case EROFS:
1390                 return AFPERR_VLOCK;
1391             default:
1392                 return( AFPERR_PARAM );
1393             }
1394         }
1395         break;  /* from the while */
1396     }
1397     /*
1398      * Does kFPDeleteInhibitBit (bit 8) set?
1399      */
1400     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1401         u_int16_t   bshort;
1402
1403         ad_getattr(&ad, &bshort);
1404         if ((bshort & htons(ATTRBIT_NODELETE))) {
1405             ad_close( &ad, adflags );
1406             return(AFPERR_OLOCK);
1407         }
1408     }
1409     
1410     if ((adflags & ADFLAGS_HF) ) {
1411         /* FIXME we have a pb here because we want to know if a file is open 
1412          * there's a 'priority inversion' if you can't open the ressource fork RW
1413          * you can delete it if it's open because you can't get a write lock.
1414          * 
1415          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1416          * metadatas
1417          *
1418          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1419          */
1420         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1421             ad_close( &ad, adflags );
1422             return( AFPERR_BUSY );
1423         }
1424     }
1425
1426     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1427         err = AFPERR_BUSY;
1428     }
1429     else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1430              !(err = netatalk_unlink( file )) ) {
1431 #ifdef CNID_DB /* get rid of entry */
1432         cnid_t id;
1433         if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file)))) 
1434         {
1435             cnid_delete(vol->v_db, id);
1436         }
1437 #endif /* CNID_DB */
1438
1439     }
1440     ad_close( &ad, adflags );  /* ad_close removes locks if any */
1441
1442 #ifdef DEBUG
1443     LOG(log_info, logtype_afpd, "end deletefile:");
1444 #endif /* DEBUG */
1445
1446     return err;
1447 }
1448
1449 /* ------------------------------------ */
1450 #ifdef CNID_DB
1451 /* return a file id */
1452 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1453 AFPObj      *obj;
1454 char    *ibuf, *rbuf;
1455 int             ibuflen, *rbuflen;
1456 {
1457     struct stat         *st;
1458     struct vol          *vol;
1459     struct dir          *dir;
1460     char                *upath;
1461     int                 len;
1462     cnid_t              did, id;
1463     u_short             vid;
1464     struct path         *s_path;
1465
1466 #ifdef DEBUG
1467     LOG(log_info, logtype_afpd, "begin afp_createid:");
1468 #endif /* DEBUG */
1469
1470     *rbuflen = 0;
1471
1472     ibuf += 2;
1473
1474     memcpy(&vid, ibuf, sizeof(vid));
1475     ibuf += sizeof(vid);
1476
1477     if (NULL == ( vol = getvolbyvid( vid )) ) {
1478         return( AFPERR_PARAM);
1479     }
1480
1481     if (vol->v_db == NULL) {
1482         return AFPERR_NOOP;
1483     }
1484
1485     if (vol->v_flags & AFPVOL_RO)
1486         return AFPERR_VLOCK;
1487
1488     memcpy(&did, ibuf, sizeof( did ));
1489     ibuf += sizeof(did);
1490
1491     if (NULL == ( dir = dirlookup( vol, did )) ) {
1492         return afp_errno; /* was AFPERR_PARAM */
1493     }
1494
1495     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1496         return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1497     }
1498
1499     if ( path_isadir(s_path) ) {
1500         return( AFPERR_BADTYPE );
1501     }
1502
1503     upath = s_path->u_name;
1504     switch (s_path->st_errno) {
1505         case 0:
1506              break; /* success */
1507         case EPERM:
1508         case EACCES:
1509             return AFPERR_ACCESS;
1510         case ENOENT:
1511             return AFPERR_NOOBJ;
1512         default:
1513             return AFPERR_PARAM;
1514     }
1515     st = &s_path->st;
1516     if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1517         memcpy(rbuf, &id, sizeof(id));
1518         *rbuflen = sizeof(id);
1519         return AFPERR_EXISTID;
1520     }
1521
1522     if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1523         memcpy(rbuf, &id, sizeof(id));
1524         *rbuflen = sizeof(id);
1525         return AFP_OK;
1526     }
1527
1528 #ifdef DEBUG
1529     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1530 #endif /* DEBUG */
1531     return afp_errno;
1532 }
1533
1534 /* ------------------------------
1535    resolve a file id */
1536 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1537 AFPObj      *obj;
1538 char    *ibuf, *rbuf;
1539 int             ibuflen, *rbuflen;
1540 {
1541     struct vol          *vol;
1542     struct dir          *dir;
1543     char                *upath;
1544     struct path         path;
1545     int                 err, buflen;
1546     cnid_t              id;
1547     u_int16_t           vid, bitmap;
1548
1549     static char buffer[12 + MAXPATHLEN + 1];
1550     int len = 12 + MAXPATHLEN + 1;
1551
1552 #ifdef DEBUG
1553     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1554 #endif /* DEBUG */
1555
1556     *rbuflen = 0;
1557     ibuf += 2;
1558
1559     memcpy(&vid, ibuf, sizeof(vid));
1560     ibuf += sizeof(vid);
1561
1562     if (NULL == ( vol = getvolbyvid( vid )) ) {
1563         return( AFPERR_PARAM);
1564     }
1565
1566     if (vol->v_db == NULL) {
1567         return AFPERR_NOOP;
1568     }
1569
1570     memcpy(&id, ibuf, sizeof( id ));
1571     ibuf += sizeof(id);
1572
1573     if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1574         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1575     }
1576
1577     if (NULL == ( dir = dirlookup( vol, id )) ) {
1578         return AFPERR_NOID; /* idem AFPERR_PARAM */
1579     }
1580     path.u_name = upath;
1581     if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1582         switch (errno) {
1583         case EACCES:
1584         case EPERM:
1585             return AFPERR_ACCESS;
1586         case ENOENT:
1587             return AFPERR_NOID;
1588         default:
1589             return AFPERR_PARAM;
1590         }
1591     }
1592     /* directories are bad */
1593     if (S_ISDIR(path.st.st_mode))
1594         return AFPERR_BADTYPE;
1595
1596     memcpy(&bitmap, ibuf, sizeof(bitmap));
1597     bitmap = ntohs( bitmap );
1598     if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1599         return AFPERR_NOID;
1600     }
1601     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
1602                             rbuf + sizeof(bitmap), &buflen))) {
1603         return err;
1604     }
1605     *rbuflen = buflen + sizeof(bitmap);
1606     memcpy(rbuf, ibuf, sizeof(bitmap));
1607
1608 #ifdef DEBUG
1609     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1610 #endif /* DEBUG */
1611
1612     return AFP_OK;
1613 }
1614
1615 /* ------------------------------ */
1616 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1617 AFPObj      *obj;
1618 char    *ibuf, *rbuf;
1619 int             ibuflen, *rbuflen;
1620 {
1621     struct stat         st;
1622     struct vol          *vol;
1623     struct dir          *dir;
1624     char                *upath;
1625     int                 err;
1626     cnid_t              id;
1627     cnid_t              fileid;
1628     u_short             vid;
1629     static char buffer[12 + MAXPATHLEN + 1];
1630     int len = 12 + MAXPATHLEN + 1;
1631
1632 #ifdef DEBUG
1633     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1634 #endif /* DEBUG */
1635
1636     *rbuflen = 0;
1637     ibuf += 2;
1638
1639     memcpy(&vid, ibuf, sizeof(vid));
1640     ibuf += sizeof(vid);
1641
1642     if (NULL == ( vol = getvolbyvid( vid )) ) {
1643         return( AFPERR_PARAM);
1644     }
1645
1646     if (vol->v_db == NULL) {
1647         return AFPERR_NOOP;
1648     }
1649
1650     if (vol->v_flags & AFPVOL_RO)
1651         return AFPERR_VLOCK;
1652
1653     memcpy(&id, ibuf, sizeof( id ));
1654     ibuf += sizeof(id);
1655     fileid = id;
1656
1657     if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1658         return AFPERR_NOID;
1659     }
1660
1661     if (NULL == ( dir = dirlookup( vol, id )) ) {
1662         return( AFPERR_PARAM );
1663     }
1664
1665     err = AFP_OK;
1666     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1667         switch (errno) {
1668         case EACCES:
1669         case EPERM:
1670             return AFPERR_ACCESS;
1671         case ENOENT:
1672             /* still try to delete the id */
1673             err = AFPERR_NOOBJ;
1674             break;
1675         default:
1676             return AFPERR_PARAM;
1677         }
1678     }
1679     else if (S_ISDIR(st.st_mode)) /* directories are bad */
1680         return AFPERR_BADTYPE;
1681
1682     if (cnid_delete(vol->v_db, fileid)) {
1683         switch (errno) {
1684         case EROFS:
1685             return AFPERR_VLOCK;
1686         case EPERM:
1687         case EACCES:
1688             return AFPERR_ACCESS;
1689         default:
1690             return AFPERR_PARAM;
1691         }
1692     }
1693
1694 #ifdef DEBUG
1695     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1696 #endif /* DEBUG */
1697
1698     return err;
1699 }
1700 #endif /* CNID_DB */
1701
1702 #define APPLETEMP ".AppleTempXXXXXX"
1703
1704 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1705 AFPObj      *obj;
1706 char    *ibuf, *rbuf;
1707 int             ibuflen, *rbuflen;
1708 {
1709     struct stat         srcst, destst;
1710     struct vol          *vol;
1711     struct dir          *dir, *sdir;
1712     char                *spath, temp[17], *p;
1713     char                *supath, *upath;
1714     struct path         *path;
1715     int                 err;
1716     struct adouble      ads;
1717     struct adouble      add;
1718     struct adouble      *adsp;
1719     struct adouble      *addp;
1720     struct ofork        *s_of;
1721     struct ofork        *d_of;
1722     int                 crossdev;
1723     
1724 #ifdef CNID_DB
1725     int                 slen, dlen;
1726 #endif /* CNID_DB */
1727     u_int32_t           sid, did;
1728     u_int16_t           vid;
1729
1730 #ifdef DEBUG
1731     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1732 #endif /* DEBUG */
1733
1734     *rbuflen = 0;
1735     ibuf += 2;
1736
1737     memcpy(&vid, ibuf, sizeof(vid));
1738     ibuf += sizeof(vid);
1739
1740     if (NULL == ( vol = getvolbyvid( vid )) ) {
1741         return( AFPERR_PARAM);
1742     }
1743
1744     if (vol->v_flags & AFPVOL_RO)
1745         return AFPERR_VLOCK;
1746
1747     /* source and destination dids */
1748     memcpy(&sid, ibuf, sizeof(sid));
1749     ibuf += sizeof(sid);
1750     memcpy(&did, ibuf, sizeof(did));
1751     ibuf += sizeof(did);
1752
1753     /* source file */
1754     if (NULL == (dir = dirlookup( vol, sid )) ) {
1755         return afp_errno; /* was AFPERR_PARAM */
1756     }
1757
1758     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1759         return get_afp_errno(AFPERR_NOOBJ); 
1760     }
1761
1762     if ( path_isadir(path) ) {
1763         return( AFPERR_BADTYPE );   /* it's a dir */
1764     }
1765
1766     upath = path->u_name;
1767     switch (path->st_errno) {
1768         case 0:
1769              break;
1770         case ENOENT:
1771             return AFPERR_NOID;
1772         case EPERM:
1773         case EACCES:
1774             return AFPERR_ACCESS;
1775         default:
1776             return AFPERR_PARAM;
1777     }
1778     memset(&ads, 0, sizeof(ads));
1779     adsp = &ads;
1780     if ((s_of = of_findname(path))) {
1781             /* reuse struct adouble so it won't break locks */
1782             adsp = s_of->of_ad;
1783     }
1784     memcpy(&srcst, &path->st, sizeof(struct stat));
1785     /* save some stuff */
1786     sdir = curdir;
1787     spath = obj->oldtmp;
1788     supath = obj->newtmp;
1789     strcpy(spath, path->m_name);
1790     strcpy(supath, upath); /* this is for the cnid changing */
1791     p = absupath( vol, sdir, upath);
1792     if (!p) {
1793         /* pathname too long */
1794         return AFPERR_PARAM ;
1795     }
1796
1797     /* look for the source cnid. if it doesn't exist, don't worry about
1798      * it. */
1799 #ifdef CNID_DB
1800     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1801                       slen = strlen(supath));
1802 #endif /* CNID_DB */
1803
1804     if (NULL == ( dir = dirlookup( vol, did )) ) {
1805         return afp_errno; /* was AFPERR_PARAM */
1806     }
1807
1808     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1809         return get_afp_errno(AFPERR_NOOBJ); 
1810     }
1811
1812     if ( path_isadir(path) ) {
1813         return( AFPERR_BADTYPE );
1814     }
1815
1816     /* FPExchangeFiles is the only call that can return the SameObj
1817      * error */
1818     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1819         return AFPERR_SAMEOBJ;
1820
1821     switch (path->st_errno) {
1822         case 0:
1823              break;
1824         case ENOENT:
1825             return AFPERR_NOID;
1826         case EPERM:
1827         case EACCES:
1828             return AFPERR_ACCESS;
1829         default:
1830             return AFPERR_PARAM;
1831     }
1832     memset(&add, 0, sizeof(add));
1833     addp = &add;
1834     if ((d_of = of_findname( path))) {
1835             /* reuse struct adouble so it won't break locks */
1836             addp = d_of->of_ad;
1837     }
1838     memcpy(&destst, &path->st, sizeof(struct stat));
1839
1840     /* they are not on the same device and at least one is open
1841     */
1842     crossdev = (srcst.st_dev != destst.st_dev);
1843     if ((d_of || s_of)  && crossdev)
1844         return AFPERR_MISC;
1845     
1846     upath = path->u_name;
1847 #ifdef CNID_DB
1848     /* look for destination id. */
1849     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1850                       dlen = strlen(upath));
1851 #endif /* CNID_DB */
1852
1853     /* construct a temp name.
1854      * NOTE: the temp file will be in the dest file's directory. it
1855      * will also be inaccessible from AFP. */
1856     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1857     if (!mktemp(temp))
1858         return AFPERR_MISC;
1859
1860     /* now, quickly rename the file. we error if we can't. */
1861     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1862         goto err_exchangefile;
1863     of_rename(vol, s_of, sdir, spath, curdir, temp);
1864
1865     /* rename destination to source */
1866     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1867         goto err_src_to_tmp;
1868     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1869
1870     /* rename temp to destination */
1871     if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1872         goto err_dest_to_src;
1873     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1874
1875 #ifdef CNID_DB
1876     /* id's need switching. src -> dest and dest -> src. 
1877      * we need to re-stat() if it was a cross device copy.
1878     */
1879     if (sid) {
1880         cnid_delete(vol->v_db, sid);
1881     }
1882     if (did) {
1883         cnid_delete(vol->v_db, did);
1884     }
1885     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
1886                 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1887        ||
1888        (sid && ( (crossdev && stat(p, &destst) < 0) ||
1889                 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1890     ) {
1891         switch (errno) {
1892         case EPERM:
1893         case EACCES:
1894             err = AFPERR_ACCESS;
1895             break;
1896         default:
1897             err = AFPERR_PARAM;
1898         }
1899         goto err_temp_to_dest;
1900     }
1901 #endif /* CNID_DB */
1902
1903 #ifdef DEBUG
1904     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1905 #endif /* DEBUG */
1906
1907     return AFP_OK;
1908
1909
1910     /* all this stuff is so that we can unwind a failed operation
1911      * properly. */
1912 #ifdef CNID_DB
1913 err_temp_to_dest:
1914 #endif
1915     /* rename dest to temp */
1916     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1917     of_rename(vol, s_of, curdir, upath, curdir, temp);
1918
1919 err_dest_to_src:
1920     /* rename source back to dest */
1921     renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1922     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1923
1924 err_src_to_tmp:
1925     /* rename temp back to source */
1926     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1927     of_rename(vol, s_of, curdir, temp, sdir, spath);
1928
1929 err_exchangefile:
1930     return err;
1931 }