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