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