2 * $Id: file.c,v 1.92.2.2.2.4 2003-10-17 00:01:11 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
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 */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
51 #include <atalk/cnid.h>
52 #include "directory.h"
61 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
62 * field bytes subfield bytes
65 * ioFlFndrInfo 16 -> type 4 type field
66 * creator 4 creator field
67 * flags 2 finder flags:
69 * location 4 location in window
70 * folder 2 window that contains file
72 * ioFlXFndrInfo 16 -> iconID 2 icon id
74 * script 1 script system
76 * commentID 2 comment id
77 * putawayID 4 home directory id
80 const u_char ufinderi[] = {
81 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
82 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0
87 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
88 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
93 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
94 memcpy(data, ad_finder, 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
109 /* ---------------------
111 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
116 aint = strlen( name );
120 if (utf8_encoding()) {
121 /* but name is an utf8 mac name */
124 /* global static variable... */
126 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
145 utf8 = htonl(vol->v_mac->kTextEncoding); /* htonl(utf8) */
146 memcpy(data, &utf8, sizeof(utf8));
147 data += sizeof(utf8);
150 memcpy(data, &temp, sizeof(temp));
151 data += sizeof(temp);
154 memcpy( data, src, aint );
164 * FIXME: PDINFO is UTF8 and doesn't need adp
166 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
167 (1 << FILPBIT_CDATE) |\
168 (1 << FILPBIT_MDATE) |\
169 (1 << FILPBIT_BDATE) |\
170 (1 << FILPBIT_FINFO) |\
171 (1 << FILPBIT_RFLEN) |\
172 (1 << FILPBIT_EXTRFLEN) |\
173 (1 << FILPBIT_PDINFO)))
175 /* -------------------------- */
176 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
177 const cnid_t did, const char *upath, const int len)
181 #if AD_VERSION > AD_VERSION1
184 char stamp[ADEDLEN_PRIVSYN];
185 /* look in AD v2 header
186 * note inode and device are opaques and not in network order
188 if (adp && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)) {
189 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
190 if ( sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)) {
191 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
192 if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
193 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
195 if (dev == st->st_dev && ino == st->st_ino && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
196 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
203 if (vol->v_cdb != NULL) {
204 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
205 /* Throw errors if cnid_add fails. */
206 if (aint == CNID_INVALID) {
208 case CNID_ERR_CLOSE: /* the db is closed */
211 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
212 afp_errno = AFPERR_PARAM;
215 afp_errno = AFPERR_PARAM;
218 afp_errno = AFPERR_MISC;
222 #if AD_VERSION > AD_VERSION1
223 else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
224 /* update the ressource fork
225 * for a folder adp is always null
227 ad_setid(adp, st, aint, vol->v_stamp);
228 ad_flush(adp, ADFLAGS_HF);
235 /* -------------------------- */
236 int getmetadata(struct vol *vol,
238 struct path *path, struct dir *dir,
239 char *buf, int *buflen, struct adouble *adp, int attrbits )
241 char *data, *l_nameoff = NULL, *upath;
242 char *utf_nameoff = NULL;
247 u_char achar, fdType[4];
253 LOG(log_info, logtype_afpd, "begin getmetadata:");
256 upath = path->u_name;
261 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
262 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
263 || (bitmap & (1 << FILPBIT_FNUM))) {
265 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
269 path->m_name = utompath(vol, upath, id, utf8_encoding());
272 while ( bitmap != 0 ) {
273 while (( bitmap & 1 ) == 0 ) {
281 ad_getattr(adp, &ashort);
282 } else if (*upath == '.') {
283 ashort = htons(ATTRBIT_INVISIBLE);
287 /* FIXME do we want a visual clue if the file is read only
290 accessmode( ".", &ma, dir , NULL);
291 if ((ma.ma_user & AR_UWRITE)) {
292 accessmode( upath, &ma, dir , st);
293 if (!(ma.ma_user & AR_UWRITE)) {
294 attrbits |= ATTRBIT_NOWRITE;
299 ashort = htons(ntohs(ashort) | attrbits);
300 memcpy(data, &ashort, sizeof( ashort ));
301 data += sizeof( ashort );
305 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
306 data += sizeof( u_int32_t );
310 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
311 aint = AD_DATE_FROM_UNIX(st->st_mtime);
312 memcpy(data, &aint, sizeof( aint ));
313 data += sizeof( aint );
317 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
318 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
319 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 memcpy(data, &aint, sizeof( int ));
325 data += sizeof( int );
329 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
330 aint = AD_DATE_START;
331 memcpy(data, &aint, sizeof( int ));
332 data += sizeof( int );
336 get_finderinfo(path->m_name, adp, (char *)data);
338 if (*upath == '.') { /* make it invisible */
339 ashort = htons(FINDERINFO_INVISIBLE);
340 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
348 data += sizeof( u_int16_t );
352 memset(data, 0, sizeof(u_int16_t));
353 data += sizeof( u_int16_t );
357 memcpy(data, &id, sizeof( id ));
358 data += sizeof( id );
362 if (st->st_size > 0xffffffff)
365 aint = htonl( st->st_size );
366 memcpy(data, &aint, sizeof( aint ));
367 data += sizeof( aint );
372 if (adp->ad_rlen > 0xffffffff)
375 aint = htonl( adp->ad_rlen);
379 memcpy(data, &aint, sizeof( aint ));
380 data += sizeof( aint );
383 /* Current client needs ProDOS info block for this file.
384 Use simple heuristic and let the Mac "type" string tell
385 us what the PD file code should be. Everything gets a
386 subtype of 0x0000 unless the original value was hashed
387 to "pXYZ" when we created it. See IA, Ver 2.
388 <shirsch@adelphia.net> */
389 case FILPBIT_PDINFO :
390 if (afp_version >= 30) { /* UTF8 name */
391 utf8 = kTextEncodingUTF8;
393 data += sizeof( u_int16_t );
395 memcpy(data, &aint, sizeof( aint ));
396 data += sizeof( aint );
400 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
402 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
406 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
418 else if ( fdType[0] == 'p' ) {
420 ashort = (fdType[2] * 256) + fdType[3];
434 memcpy(data, &ashort, sizeof( ashort ));
435 data += sizeof( ashort );
436 memset(data, 0, sizeof( ashort ));
437 data += sizeof( ashort );
440 case FILPBIT_EXTDFLEN:
441 aint = htonl(st->st_size >> 32);
442 memcpy(data, &aint, sizeof( aint ));
443 data += sizeof( aint );
444 aint = htonl(st->st_size);
445 memcpy(data, &aint, sizeof( aint ));
446 data += sizeof( aint );
448 case FILPBIT_EXTRFLEN:
451 aint = htonl(adp->ad_rlen >> 32);
452 memcpy(data, &aint, sizeof( aint ));
453 data += sizeof( aint );
455 aint = htonl(adp->ad_rlen);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
459 case FILPBIT_UNIXPR :
460 aint = htonl(st->st_uid);
461 memcpy( data, &aint, sizeof( aint ));
462 data += sizeof( aint );
463 aint = htonl(st->st_gid);
464 memcpy( data, &aint, sizeof( aint ));
465 data += sizeof( aint );
467 aint = htonl(st->st_mode);
468 memcpy( data, &aint, sizeof( aint ));
469 data += sizeof( aint );
471 accessmode( upath, &ma, dir , st);
473 *data++ = ma.ma_user;
474 *data++ = ma.ma_world;
475 *data++ = ma.ma_group;
476 *data++ = ma.ma_owner;
480 return( AFPERR_BITMAP );
486 ashort = htons( data - buf );
487 memcpy(l_nameoff, &ashort, sizeof( ashort ));
488 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
491 ashort = htons( data - buf );
492 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
493 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
495 *buflen = data - buf;
499 /* ----------------------- */
500 int getfilparams(struct vol *vol,
502 struct path *path, struct dir *dir,
503 char *buf, int *buflen )
505 struct adouble ad, *adp;
508 u_int16_t attrbits = 0;
513 LOG(log_info, logtype_default, "begin getfilparams:");
516 opened = PARAM_NEED_ADP(bitmap);
519 upath = path->u_name;
520 if ((of = of_findname(path))) {
522 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
523 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
525 ad_init(&ad, vol->v_adouble);
529 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
534 we need to check if the file is open by another process.
535 it's slow so we only do it if we have to:
536 - bitmap is requested.
537 - we don't already have the answer!
539 if ((bitmap & (1 << FILPBIT_ATTR))) {
540 if (!(attrbits & ATTRBIT_ROPEN)) {
542 if (!(attrbits & ATTRBIT_DOPEN)) {
547 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
549 ad_close( adp, ADFLAGS_HF );
552 LOG(log_info, logtype_afpd, "end getfilparams:");
558 /* ----------------------------- */
559 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
562 int ibuflen, *rbuflen;
564 struct adouble ad, *adp;
567 struct ofork *of = NULL;
569 int creatf, did, openf, retvalue = AFP_OK;
575 LOG(log_info, logtype_afpd, "begin afp_createfile:");
580 creatf = (unsigned char) *ibuf++;
582 memcpy(&vid, ibuf, sizeof( vid ));
583 ibuf += sizeof( vid );
585 if (NULL == ( vol = getvolbyvid( vid )) ) {
586 return( AFPERR_PARAM );
589 if (vol->v_flags & AFPVOL_RO)
592 memcpy(&did, ibuf, sizeof( did));
593 ibuf += sizeof( did );
595 if (NULL == ( dir = dirlookup( vol, did )) ) {
599 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
600 return get_afp_errno(AFPERR_PARAM);
603 if ( *s_path->m_name == '\0' ) {
604 return( AFPERR_BADTYPE );
607 upath = s_path->u_name;
608 if (0 != (ret = check_name(vol, upath)))
611 /* if upath is deleted we already in trouble anyway */
612 if ((of = of_findname(s_path))) {
615 ad_init(&ad, vol->v_adouble);
619 /* on a hard create, fail if file exists and is open */
622 openf = O_RDWR|O_CREAT|O_TRUNC;
624 /* on a soft create, if the file is open then ad_open won't fail
625 because open syscall is not called
630 openf = O_RDWR|O_CREAT|O_EXCL;
633 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
634 openf, 0666, adp) < 0 ) {
638 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
639 return ( AFPERR_NOOBJ );
641 return( AFPERR_EXIST );
643 return( AFPERR_ACCESS );
645 return( AFPERR_PARAM );
648 if ( ad_hfileno( adp ) == -1 ) {
649 /* on noadouble volumes, just creating the data fork is ok */
650 if (vol_noadouble(vol)) {
651 ad_close( adp, ADFLAGS_DF );
652 goto createfile_done;
654 /* FIXME with hard create on an existing file, we already
655 * corrupted the data file.
657 netatalk_unlink( upath );
658 ad_close( adp, ADFLAGS_DF );
659 return AFPERR_ACCESS;
662 path = s_path->m_name;
663 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
664 memcpy(ad_entry( adp, ADEID_NAME ), path,
665 ad_getentrylen( adp, ADEID_NAME ));
666 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
667 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
673 if (vol->v_flags & AFPVOL_DROPBOX) {
674 retvalue = matchfile2dirperms(upath, vol, did);
676 #endif /* DROPKLUDGE */
678 setvoltime(obj, vol );
681 LOG(log_info, logtype_afpd, "end afp_createfile");
687 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
690 int ibuflen, *rbuflen;
696 u_int16_t vid, bitmap;
699 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
705 memcpy(&vid, ibuf, sizeof( vid ));
706 ibuf += sizeof( vid );
707 if (NULL == ( vol = getvolbyvid( vid )) ) {
708 return( AFPERR_PARAM );
711 if (vol->v_flags & AFPVOL_RO)
714 memcpy(&did, ibuf, sizeof( did ));
715 ibuf += sizeof( did );
716 if (NULL == ( dir = dirlookup( vol, did )) ) {
717 return afp_errno; /* was AFPERR_NOOBJ */
720 memcpy(&bitmap, ibuf, sizeof( bitmap ));
721 bitmap = ntohs( bitmap );
722 ibuf += sizeof( bitmap );
724 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
725 return get_afp_errno(AFPERR_PARAM);
728 if (path_isadir(s_path)) {
729 return( AFPERR_BADTYPE ); /* it's a directory */
732 if ( s_path->st_errno != 0 ) {
733 return( AFPERR_NOOBJ );
736 if ((u_long)ibuf & 1 ) {
740 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
741 setvoltime(obj, vol );
745 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
752 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
755 extern struct path Cur_Path;
757 int setfilparams(struct vol *vol,
758 struct path *path, u_int16_t bitmap, char *buf )
760 struct adouble ad, *adp;
763 int bit = 0, isad = 1, err = AFP_OK;
765 u_char achar, *fdType, xyy[4];
766 u_int16_t ashort, bshort;
770 int change_mdate = 0;
771 int change_parent_mdate = 0;
777 LOG(log_info, logtype_afpd, "begin setfilparams:");
780 upath = path->u_name;
781 if ((of = of_findname(path))) {
784 ad_init(&ad, vol->v_adouble);
788 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
789 return AFPERR_ACCESS;
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;
799 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
800 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
801 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
802 ad_getentrylen( adp, ADEID_NAME ));
805 while ( bitmap != 0 ) {
806 while (( bitmap & 1 ) == 0 ) {
814 memcpy(&ashort, buf, sizeof( ashort ));
815 ad_getattr(adp, &bshort);
816 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
817 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
821 if ((ashort & htons(ATTRBIT_INVISIBLE)))
822 change_parent_mdate = 1;
823 ad_setattr(adp, bshort);
824 buf += sizeof( ashort );
829 memcpy(&aint, buf, sizeof(aint));
830 ad_setdate(adp, AD_DATE_CREATE, aint);
831 buf += sizeof( aint );
835 memcpy(&newdate, buf, sizeof( newdate ));
836 buf += sizeof( newdate );
841 memcpy(&aint, buf, sizeof(aint));
842 ad_setdate(adp, AD_DATE_BACKUP, aint);
843 buf += sizeof( aint );
849 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
851 ((em = getextmap( path->m_name )) &&
852 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
853 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
854 || ((em = getdefextmap()) &&
855 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
856 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
858 memcpy(buf, ufinderi, 8 );
861 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
865 /* Client needs to set the ProDOS file info for this file.
866 Use a defined string for TEXT to support crlf
867 translations and convert all else into pXYY per Inside
868 Appletalk. Always set the creator as "pdos". Changes
869 from original by Marsha Jackson. */
870 case FILPBIT_PDINFO :
871 if (afp_version < 30) { /* else it's UTF8 name */
874 /* Keep special case to support crlf translations */
875 if ((unsigned int) achar == 0x04) {
876 fdType = (u_char *)"TEXT";
879 xyy[0] = ( u_char ) 'p';
885 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
886 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
890 case FILPBIT_UNIXPR :
891 /* Skip the UIG/GID, no way to set them from OSX clients */
892 buf += sizeof( aint );
893 buf += sizeof( aint );
896 change_parent_mdate = 1;
897 memcpy( &aint, buf, sizeof( aint ));
898 buf += sizeof( aint );
901 setfilemode(path, aint);
905 goto setfilparam_done;
913 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
914 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
918 ad_setdate(adp, AD_DATE_MODIFY, newdate);
919 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
924 ad_flush( adp, ADFLAGS_HF );
925 ad_close( adp, ADFLAGS_HF );
929 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
930 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
931 bitmap = 1<<FILPBIT_MDATE;
932 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
936 LOG(log_info, logtype_afpd, "end setfilparams:");
942 * renamefile and copyfile take the old and new unix pathnames
943 * and the new mac name.
945 * src the source path
946 * dst the dest filename in current dir
947 * newname the dest mac name
948 * adp adouble struct of src file, if open, or & zeroed one
951 int renamefile(src, dst, newname, noadouble, adp )
952 char *src, *dst, *newname;
956 char adsrc[ MAXPATHLEN + 1];
961 LOG(log_info, logtype_afpd, "begin renamefile:");
964 if ( unix_rename( src, dst ) < 0 ) {
967 return( AFPERR_NOOBJ );
970 return( AFPERR_ACCESS );
973 case EXDEV : /* Cross device move -- try copy */
974 /* NOTE: with open file it's an error because after the copy we will
975 * get two files, it's fixable for our process (eg reopen the new file, get the
976 * locks, and so on. But it doesn't solve the case with a second process
978 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
979 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
980 return AFPERR_OLOCK; /* little lie */
982 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
983 /* on error copyfile delete dest */
986 return deletefile(NULL, src, 0);
988 return( AFPERR_PARAM );
992 strcpy( adsrc, ad_path( src, 0 ));
994 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
999 if (errno == ENOENT) {
1002 if (stat(adsrc, &st)) /* source has no ressource fork, */
1005 /* We are here because :
1006 * -there's no dest folder.
1007 * -there's no .AppleDouble in the dest folder.
1008 * if we use the struct adouble passed in parameter it will not
1009 * create .AppleDouble if the file is already opened, so we
1010 * use a diff one, it's not a pb,ie it's not the same file, yet.
1012 ad_init(&ad, AD_VERSION); /* FIXME */
1013 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1014 ad_close(&ad, ADFLAGS_HF);
1015 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
1020 else { /* it's something else, bail out */
1024 /* try to undo the data fork rename,
1025 * we know we are on the same device
1028 unix_rename( dst, src );
1029 /* return the first error */
1032 return AFPERR_NOOBJ;
1035 return AFPERR_ACCESS ;
1037 return AFPERR_VLOCK;
1039 return AFPERR_PARAM ;
1044 /* don't care if we can't open the newly renamed ressource fork
1046 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1047 len = strlen( newname );
1048 ad_setentrylen( adp, ADEID_NAME, len );
1049 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1050 ad_flush( adp, ADFLAGS_HF );
1051 ad_close( adp, ADFLAGS_HF );
1054 LOG(log_info, logtype_afpd, "end renamefile:");
1060 int copy_path_name(char *newname, char *ibuf)
1067 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1073 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1074 strncpy( newname, ibuf, plen );
1075 newname[ plen ] = '\0';
1076 if (strlen(newname) != plen) {
1077 /* there's \0 in newname, e.g. it's a pathname not
1085 memcpy(&hint, ibuf, sizeof(hint));
1086 ibuf += sizeof(hint);
1088 memcpy(&len16, ibuf, sizeof(len16));
1089 ibuf += sizeof(len16);
1090 plen = ntohs(len16);
1093 if (plen > AFPOBJ_TMPSIZ) {
1096 strncpy( newname, ibuf, plen );
1097 newname[ plen ] = '\0';
1098 if (strlen(newname) != plen) {
1107 /* -----------------------------------
1109 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1112 int ibuflen, *rbuflen;
1116 char *newname, *p, *upath;
1117 struct path *s_path;
1118 u_int32_t sdid, ddid;
1119 int err, retvalue = AFP_OK;
1120 u_int16_t svid, dvid;
1123 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1129 memcpy(&svid, ibuf, sizeof( svid ));
1130 ibuf += sizeof( svid );
1131 if (NULL == ( vol = getvolbyvid( svid )) ) {
1132 return( AFPERR_PARAM );
1135 memcpy(&sdid, ibuf, sizeof( sdid ));
1136 ibuf += sizeof( sdid );
1137 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1141 memcpy(&dvid, ibuf, sizeof( dvid ));
1142 ibuf += sizeof( dvid );
1143 memcpy(&ddid, ibuf, sizeof( ddid ));
1144 ibuf += sizeof( ddid );
1146 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1147 return get_afp_errno(AFPERR_PARAM);
1149 if ( path_isadir(s_path) ) {
1150 return( AFPERR_BADTYPE );
1153 /* don't allow copies when the file is open.
1154 * XXX: the spec only calls for read/deny write access.
1155 * however, copyfile doesn't have any of that info,
1156 * and locks need to stay coherent. as a result,
1157 * we just balk if the file is opened already. */
1159 newname = obj->newtmp;
1160 strcpy( newname, s_path->m_name );
1162 if (of_findname(s_path))
1163 return AFPERR_DENYCONF;
1165 p = ctoupath( vol, curdir, newname );
1167 return AFPERR_PARAM;
1171 /* FIXME svid != dvid && dvid's user can't read svid */
1173 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1174 return( AFPERR_PARAM );
1177 if (vol->v_flags & AFPVOL_RO)
1178 return AFPERR_VLOCK;
1180 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1184 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1185 return get_afp_errno(AFPERR_NOOBJ);
1187 if ( *s_path->m_name != '\0' ) {
1189 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1191 path_error(s_path, AFPERR_PARAM);
1194 /* one of the handful of places that knows about the path type */
1195 if (copy_path_name(newname, ibuf) < 0) {
1196 return( AFPERR_PARAM );
1198 /* newname is always only a filename so curdir *is* its
1201 if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
1202 return( AFPERR_PARAM );
1204 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1210 if (vol->v_flags & AFPVOL_DROPBOX) {
1211 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1213 #endif /* DROPKLUDGE */
1215 setvoltime(obj, vol );
1218 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1225 static __inline__ int copy_all(const int dfd, const void *buf,
1231 LOG(log_info, logtype_afpd, "begin copy_all:");
1234 while (buflen > 0) {
1235 if ((cc = write(dfd, buf, buflen)) < 0) {
1242 return AFPERR_DFULL;
1244 return AFPERR_VLOCK;
1246 return AFPERR_PARAM;
1253 LOG(log_info, logtype_afpd, "end copy_all:");
1259 /* -------------------------- */
1260 static int copy_fd(int dfd, int sfd)
1266 #ifdef SENDFILE_FLAVOR_LINUX
1270 #define BUF 128*1024*1024
1272 if (fstat(sfd, &st) == 0) {
1275 if ( offset >= st.st_size) {
1278 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1279 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1282 case EINVAL: /* there's no guarantee that all fs support sendfile */
1287 return AFPERR_DFULL;
1289 return AFPERR_VLOCK;
1291 return AFPERR_PARAM;
1300 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1307 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1313 /* ----------------------------------
1314 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1315 * because we are doing it elsewhere.
1317 int copyfile(src, dst, newname, noadouble )
1318 char *src, *dst, *newname;
1319 const int noadouble;
1321 struct adouble ads, add;
1322 int len, err = AFP_OK;
1326 LOG(log_info, logtype_afpd, "begin copyfile:");
1329 ad_init(&ads, 0); /* OK */
1330 ad_init(&add, 0); /* FIXME */
1331 adflags = ADFLAGS_DF;
1333 adflags |= ADFLAGS_HF;
1336 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1339 return( AFPERR_NOOBJ );
1341 return( AFPERR_ACCESS );
1343 return( AFPERR_PARAM );
1346 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1347 ad_close( &ads, adflags );
1348 if (EEXIST != (err = errno)) {
1349 deletefile(NULL, dst, 0);
1353 return AFPERR_EXIST;
1355 return( AFPERR_NOOBJ );
1357 return( AFPERR_ACCESS );
1359 return AFPERR_VLOCK;
1361 return( AFPERR_PARAM );
1364 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1365 /* copy the data fork */
1366 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1370 len = strlen( newname );
1371 ad_setentrylen( &add, ADEID_NAME, len );
1372 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1375 ad_close( &ads, adflags );
1376 ad_flush( &add, adflags );
1377 if (ad_close( &add, adflags ) <0) {
1380 if (err != AFP_OK) {
1381 deletefile(NULL, dst, 0);
1384 return( AFPERR_NOOBJ );
1386 return( AFPERR_ACCESS );
1388 return( AFPERR_PARAM );
1393 LOG(log_info, logtype_afpd, "end copyfile:");
1400 /* -----------------------------------
1401 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1402 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1404 when deletefile is called we don't have lock on it, file is closed (for us)
1405 untrue if called by renamefile
1407 ad_open always try to open file RDWR first and ad_lock takes care of
1408 WRITE lock on read only file.
1410 int deletefile( vol, file, checkAttrib )
1416 int adflags, err = AFP_OK;
1419 LOG(log_info, logtype_afpd, "begin deletefile:");
1422 /* try to open both forks at once */
1423 adflags = ADFLAGS_DF|ADFLAGS_HF;
1425 ad_init(&ad, 0); /* OK */
1426 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1429 if (adflags == ADFLAGS_DF)
1430 return AFPERR_NOOBJ;
1432 /* that failed. now try to open just the data fork */
1433 adflags = ADFLAGS_DF;
1437 return AFPERR_ACCESS;
1439 return AFPERR_VLOCK;
1441 return( AFPERR_PARAM );
1444 break; /* from the while */
1447 * Does kFPDeleteInhibitBit (bit 8) set?
1449 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1452 ad_getattr(&ad, &bshort);
1453 if ((bshort & htons(ATTRBIT_NODELETE))) {
1454 ad_close( &ad, adflags );
1455 return(AFPERR_OLOCK);
1459 if ((adflags & ADFLAGS_HF) ) {
1460 /* FIXME we have a pb here because we want to know if a file is open
1461 * there's a 'priority inversion' if you can't open the ressource fork RW
1462 * you can delete it if it's open because you can't get a write lock.
1464 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1467 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1469 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1470 ad_close( &ad, adflags );
1471 return( AFPERR_BUSY );
1475 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1478 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1479 !(err = netatalk_unlink( file )) ) {
1481 if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1483 cnid_delete(vol->v_cdb, id);
1487 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1490 LOG(log_info, logtype_afpd, "end deletefile:");
1496 /* ------------------------------------ */
1497 /* return a file id */
1498 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1501 int ibuflen, *rbuflen;
1510 struct path *s_path;
1513 LOG(log_info, logtype_afpd, "begin afp_createid:");
1520 memcpy(&vid, ibuf, sizeof(vid));
1521 ibuf += sizeof(vid);
1523 if (NULL == ( vol = getvolbyvid( vid )) ) {
1524 return( AFPERR_PARAM);
1527 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1531 if (vol->v_flags & AFPVOL_RO)
1532 return AFPERR_VLOCK;
1534 memcpy(&did, ibuf, sizeof( did ));
1535 ibuf += sizeof(did);
1537 if (NULL == ( dir = dirlookup( vol, did )) ) {
1538 return afp_errno; /* was AFPERR_PARAM */
1541 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1542 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1545 if ( path_isadir(s_path) ) {
1546 return( AFPERR_BADTYPE );
1549 upath = s_path->u_name;
1550 switch (s_path->st_errno) {
1552 break; /* success */
1555 return AFPERR_ACCESS;
1557 return AFPERR_NOOBJ;
1559 return AFPERR_PARAM;
1562 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1563 memcpy(rbuf, &id, sizeof(id));
1564 *rbuflen = sizeof(id);
1565 return AFPERR_EXISTID;
1568 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1569 memcpy(rbuf, &id, sizeof(id));
1570 *rbuflen = sizeof(id);
1575 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1580 /* ------------------------------
1581 resolve a file id */
1582 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1585 int ibuflen, *rbuflen;
1593 u_int16_t vid, bitmap;
1595 static char buffer[12 + MAXPATHLEN + 1];
1596 int len = 12 + MAXPATHLEN + 1;
1599 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1605 memcpy(&vid, ibuf, sizeof(vid));
1606 ibuf += sizeof(vid);
1608 if (NULL == ( vol = getvolbyvid( vid )) ) {
1609 return( AFPERR_PARAM);
1612 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1616 memcpy(&id, ibuf, sizeof( id ));
1620 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1621 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1624 if (NULL == ( dir = dirlookup( vol, id )) ) {
1625 return AFPERR_NOID; /* idem AFPERR_PARAM */
1627 path.u_name = upath;
1628 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1632 return AFPERR_ACCESS;
1636 return AFPERR_PARAM;
1639 /* directories are bad */
1640 if (S_ISDIR(path.st.st_mode))
1641 return AFPERR_BADTYPE;
1643 memcpy(&bitmap, ibuf, sizeof(bitmap));
1644 bitmap = ntohs( bitmap );
1645 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1648 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1649 rbuf + sizeof(bitmap), &buflen))) {
1652 *rbuflen = buflen + sizeof(bitmap);
1653 memcpy(rbuf, ibuf, sizeof(bitmap));
1656 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1662 /* ------------------------------ */
1663 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1666 int ibuflen, *rbuflen;
1676 static char buffer[12 + MAXPATHLEN + 1];
1677 int len = 12 + MAXPATHLEN + 1;
1680 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1686 memcpy(&vid, ibuf, sizeof(vid));
1687 ibuf += sizeof(vid);
1689 if (NULL == ( vol = getvolbyvid( vid )) ) {
1690 return( AFPERR_PARAM);
1693 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1697 if (vol->v_flags & AFPVOL_RO)
1698 return AFPERR_VLOCK;
1700 memcpy(&id, ibuf, sizeof( id ));
1704 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1708 if (NULL == ( dir = dirlookup( vol, id )) ) {
1709 return( AFPERR_PARAM );
1713 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1717 return AFPERR_ACCESS;
1719 /* still try to delete the id */
1723 return AFPERR_PARAM;
1726 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1727 return AFPERR_BADTYPE;
1729 if (cnid_delete(vol->v_cdb, fileid)) {
1732 return AFPERR_VLOCK;
1735 return AFPERR_ACCESS;
1737 return AFPERR_PARAM;
1742 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1748 #define APPLETEMP ".AppleTempXXXXXX"
1750 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1753 int ibuflen, *rbuflen;
1755 struct stat srcst, destst;
1757 struct dir *dir, *sdir;
1758 char *spath, temp[17], *p;
1759 char *supath, *upath;
1764 struct adouble *adsp;
1765 struct adouble *addp;
1775 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1781 memcpy(&vid, ibuf, sizeof(vid));
1782 ibuf += sizeof(vid);
1784 if (NULL == ( vol = getvolbyvid( vid )) ) {
1785 return( AFPERR_PARAM);
1788 if (vol->v_flags & AFPVOL_RO)
1789 return AFPERR_VLOCK;
1791 /* source and destination dids */
1792 memcpy(&sid, ibuf, sizeof(sid));
1793 ibuf += sizeof(sid);
1794 memcpy(&did, ibuf, sizeof(did));
1795 ibuf += sizeof(did);
1798 if (NULL == (dir = dirlookup( vol, sid )) ) {
1799 return afp_errno; /* was AFPERR_PARAM */
1802 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1803 return get_afp_errno(AFPERR_NOOBJ);
1806 if ( path_isadir(path) ) {
1807 return( AFPERR_BADTYPE ); /* it's a dir */
1810 upath = path->u_name;
1811 switch (path->st_errno) {
1818 return AFPERR_ACCESS;
1820 return AFPERR_PARAM;
1822 ad_init(&ads, vol->v_adouble);
1824 if ((s_of = of_findname(path))) {
1825 /* reuse struct adouble so it won't break locks */
1828 memcpy(&srcst, &path->st, sizeof(struct stat));
1829 /* save some stuff */
1831 spath = obj->oldtmp;
1832 supath = obj->newtmp;
1833 strcpy(spath, path->m_name);
1834 strcpy(supath, upath); /* this is for the cnid changing */
1835 p = absupath( vol, sdir, upath);
1837 /* pathname too long */
1838 return AFPERR_PARAM ;
1841 /* look for the source cnid. if it doesn't exist, don't worry about
1843 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1845 if (NULL == ( dir = dirlookup( vol, did )) ) {
1846 return afp_errno; /* was AFPERR_PARAM */
1849 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1850 return get_afp_errno(AFPERR_NOOBJ);
1853 if ( path_isadir(path) ) {
1854 return( AFPERR_BADTYPE );
1857 /* FPExchangeFiles is the only call that can return the SameObj
1859 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1860 return AFPERR_SAMEOBJ;
1862 switch (path->st_errno) {
1869 return AFPERR_ACCESS;
1871 return AFPERR_PARAM;
1873 ad_init(&add, vol->v_adouble);
1875 if ((d_of = of_findname( path))) {
1876 /* reuse struct adouble so it won't break locks */
1879 memcpy(&destst, &path->st, sizeof(struct stat));
1881 /* they are not on the same device and at least one is open
1883 crossdev = (srcst.st_dev != destst.st_dev);
1884 if ((d_of || s_of) && crossdev)
1887 upath = path->u_name;
1888 /* look for destination id. */
1889 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1891 /* construct a temp name.
1892 * NOTE: the temp file will be in the dest file's directory. it
1893 * will also be inaccessible from AFP. */
1894 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1898 /* now, quickly rename the file. we error if we can't. */
1899 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1900 goto err_exchangefile;
1901 of_rename(vol, s_of, sdir, spath, curdir, temp);
1903 /* rename destination to source */
1904 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1905 goto err_src_to_tmp;
1906 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1908 /* rename temp to destination */
1909 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1910 goto err_dest_to_src;
1911 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1913 /* id's need switching. src -> dest and dest -> src.
1914 * we need to re-stat() if it was a cross device copy.
1917 cnid_delete(vol->v_cdb, sid);
1920 cnid_delete(vol->v_cdb, did);
1922 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1923 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
1925 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1926 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
1931 err = AFPERR_ACCESS;
1936 goto err_temp_to_dest;
1940 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1946 /* all this stuff is so that we can unwind a failed operation
1949 /* rename dest to temp */
1950 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1951 of_rename(vol, s_of, curdir, upath, curdir, temp);
1954 /* rename source back to dest */
1955 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1956 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1959 /* rename temp back to source */
1960 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1961 of_rename(vol, s_of, curdir, temp, sdir, spath);