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