2 * $Id: file.c,v 1.92 2003-04-26 16:53:44 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>
52 #include <atalk/cnid.h>
54 #include "directory.h"
62 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63 * field bytes subfield bytes
66 * ioFlFndrInfo 16 -> type 4 type field
67 * creator 4 creator field
68 * flags 2 finder flags:
70 * location 4 location in window
71 * folder 2 window that contains file
73 * ioFlXFndrInfo 16 -> iconID 2 icon id
75 * script 1 script system
77 * commentID 2 comment id
78 * putawayID 4 home directory id
81 const u_char ufinderi[] = {
82 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0
88 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
94 memcpy(data, ad_entry(adp, ADEID_FINDERI), 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, char *name, 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, 1)) || !(m = utompath(vol, u, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
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)
183 aint = cnid_add(vol->v_db, st, did, upath, len, aint);
184 /* Throw errors if cnid_add fails. */
185 if (aint == CNID_INVALID) {
187 case CNID_ERR_CLOSE: /* the db is closed */
190 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
191 afp_errno = AFPERR_PARAM;
194 afp_errno = AFPERR_PARAM;
197 afp_errno = AFPERR_MISC;
205 * First thing: DID and FNUMs are
206 * in the same space for purposes of enumerate (and several
207 * other wierd places). While we consider this Apple's bug,
208 * this is the work-around: In order to maintain constant and
209 * unique DIDs and FNUMs, we monotonically generate the DIDs
210 * during the session, and derive the FNUMs from the filesystem.
211 * Since the DIDs are small, we insure that the FNUMs are fairly
212 * large by setting thier high bits to the device number.
214 * AFS already does something very similar to this for the
215 * inode number, so we don't repeat the procedure.
218 * due to complaints over did's being non-persistent,
219 * here's the current hack to provide semi-persistent
221 * 1) we reserve the first bit for file ids.
222 * 2) the next 7 bits are for the device.
223 * 3) the remaining 24 bits are for the inode.
225 * both the inode and device information are actually hashes
226 * that are then truncated to the requisite bit length.
228 * it should be okay to use lstat to deal with symlinks.
231 if ( S_ISDIR(st->st_mode)) {
232 aint = htonl( vol->v_lastdid++ );
236 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
238 #else /* USE_LASTDID */
241 const struct stat *lstp;
243 lstp = lstat(upath, &lst) < 0 ? st : &lst;
244 aint = htonl(CNID(lstp, 1));
246 #endif /* USE_LASTDID */
251 /* -------------------------- */
252 int getmetadata(struct vol *vol,
254 struct path *path, struct dir *dir,
255 char *buf, int *buflen, struct adouble *adp, int attrbits )
257 char *data, *l_nameoff = NULL, *upath;
258 char *utf_nameoff = NULL;
262 u_char achar, fdType[4];
266 LOG(log_info, logtype_afpd, "begin getmetadata:");
269 upath = path->u_name;
273 while ( bitmap != 0 ) {
274 while (( bitmap & 1 ) == 0 ) {
282 ad_getattr(adp, &ashort);
283 } else if (*upath == '.') {
284 ashort = htons(ATTRBIT_INVISIBLE);
288 /* FIXME do we want a visual clue if the file is read only
291 accessmode( ".", &ma, dir , NULL);
292 if ((ma.ma_user & AR_UWRITE)) {
293 accessmode( upath, &ma, dir , st);
294 if (!(ma.ma_user & AR_UWRITE)) {
295 attrbits |= ATTRBIT_NOWRITE;
300 ashort = htons(ntohs(ashort) | attrbits);
301 memcpy(data, &ashort, sizeof( ashort ));
302 data += sizeof( ashort );
306 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
307 data += sizeof( u_int32_t );
311 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
312 aint = AD_DATE_FROM_UNIX(st->st_mtime);
313 memcpy(data, &aint, sizeof( aint ));
314 data += sizeof( aint );
318 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
319 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
320 aint = AD_DATE_FROM_UNIX(st->st_mtime);
323 aint = AD_DATE_FROM_UNIX(st->st_mtime);
325 memcpy(data, &aint, sizeof( int ));
326 data += sizeof( int );
330 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
331 aint = AD_DATE_START;
332 memcpy(data, &aint, sizeof( int ));
333 data += sizeof( int );
337 get_finderinfo(path->m_name, adp, (char *)data);
339 if (*upath == '.') { /* make it invisible */
340 ashort = htons(FINDERINFO_INVISIBLE);
341 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
349 data += sizeof( u_int16_t );
353 memset(data, 0, sizeof(u_int16_t));
354 data += sizeof( u_int16_t );
358 aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
361 memcpy(data, &aint, sizeof( aint ));
362 data += sizeof( aint );
366 if (st->st_size > 0xffffffff)
369 aint = htonl( st->st_size );
370 memcpy(data, &aint, sizeof( aint ));
371 data += sizeof( aint );
376 if (adp->ad_rlen > 0xffffffff)
379 aint = htonl( adp->ad_rlen);
383 memcpy(data, &aint, sizeof( aint ));
384 data += sizeof( aint );
387 /* Current client needs ProDOS info block for this file.
388 Use simple heuristic and let the Mac "type" string tell
389 us what the PD file code should be. Everything gets a
390 subtype of 0x0000 unless the original value was hashed
391 to "pXYZ" when we created it. See IA, Ver 2.
392 <shirsch@adelphia.net> */
393 case FILPBIT_PDINFO :
394 if (afp_version >= 30) { /* UTF8 name */
395 utf8 = kTextEncodingUTF8;
397 data += sizeof( u_int16_t );
399 memcpy(data, &aint, sizeof( aint ));
400 data += sizeof( aint );
404 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
406 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
418 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
422 else if ( fdType[0] == 'p' ) {
424 ashort = (fdType[2] * 256) + fdType[3];
438 memcpy(data, &ashort, sizeof( ashort ));
439 data += sizeof( ashort );
440 memset(data, 0, sizeof( ashort ));
441 data += sizeof( ashort );
444 case FILPBIT_EXTDFLEN:
445 aint = htonl(st->st_size >> 32);
446 memcpy(data, &aint, sizeof( aint ));
447 data += sizeof( aint );
448 aint = htonl(st->st_size);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 case FILPBIT_EXTRFLEN:
455 aint = htonl(adp->ad_rlen >> 32);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
459 aint = htonl(adp->ad_rlen);
460 memcpy(data, &aint, sizeof( aint ));
461 data += sizeof( aint );
464 return( AFPERR_BITMAP );
470 ashort = htons( data - buf );
471 memcpy(l_nameoff, &ashort, sizeof( ashort ));
472 data = set_name(vol, data, path->m_name, 0);
475 ashort = htons( data - buf );
476 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
477 data = set_name(vol, data, path->m_name, utf8);
479 *buflen = data - buf;
483 /* ----------------------- */
484 int getfilparams(struct vol *vol,
486 struct path *path, struct dir *dir,
487 char *buf, int *buflen )
489 struct adouble ad, *adp;
492 u_int16_t attrbits = 0;
497 LOG(log_info, logtype_default, "begin getfilparams:");
500 opened = PARAM_NEED_ADP(bitmap);
503 upath = path->u_name;
504 if ((of = of_findname(path))) {
506 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
507 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
509 memset(&ad, 0, sizeof(ad));
513 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
518 we need to check if the file is open by another process.
519 it's slow so we only do it if we have to:
520 - bitmap is requested.
521 - we don't already have the answer!
523 if ((bitmap & (1 << FILPBIT_ATTR))) {
524 if (!(attrbits & ATTRBIT_ROPEN)) {
526 if (!(attrbits & ATTRBIT_DOPEN)) {
531 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
533 ad_close( adp, ADFLAGS_HF );
536 LOG(log_info, logtype_afpd, "end getfilparams:");
542 /* ----------------------------- */
543 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
546 int ibuflen, *rbuflen;
548 struct adouble ad, *adp;
551 struct ofork *of = NULL;
553 int creatf, did, openf, retvalue = AFP_OK;
559 LOG(log_info, logtype_afpd, "begin afp_createfile:");
564 creatf = (unsigned char) *ibuf++;
566 memcpy(&vid, ibuf, sizeof( vid ));
567 ibuf += sizeof( vid );
569 if (NULL == ( vol = getvolbyvid( vid )) ) {
570 return( AFPERR_PARAM );
573 if (vol->v_flags & AFPVOL_RO)
576 memcpy(&did, ibuf, sizeof( did));
577 ibuf += sizeof( did );
579 if (NULL == ( dir = dirlookup( vol, did )) ) {
583 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
584 return get_afp_errno(AFPERR_PARAM);
587 if ( *s_path->m_name == '\0' ) {
588 return( AFPERR_BADTYPE );
591 upath = s_path->u_name;
592 if (0 != (ret = check_name(vol, upath)))
595 /* if upath is deleted we already in trouble anyway */
596 if ((of = of_findname(s_path))) {
599 memset(&ad, 0, sizeof(ad));
603 /* on a hard create, fail if file exists and is open */
606 openf = O_RDWR|O_CREAT|O_TRUNC;
608 /* on a soft create, if the file is open then ad_open won't fail
609 because open syscall is not called
614 openf = O_RDWR|O_CREAT|O_EXCL;
617 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
618 openf, 0666, adp) < 0 ) {
622 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
623 return ( AFPERR_NOOBJ );
625 return( AFPERR_EXIST );
627 return( AFPERR_ACCESS );
629 return( AFPERR_PARAM );
632 if ( ad_hfileno( adp ) == -1 ) {
633 /* on noadouble volumes, just creating the data fork is ok */
634 if (vol_noadouble(vol)) {
635 ad_close( adp, ADFLAGS_DF );
636 goto createfile_done;
638 /* FIXME with hard create on an existing file, we already
639 * corrupted the data file.
641 netatalk_unlink( upath );
642 ad_close( adp, ADFLAGS_DF );
643 return AFPERR_ACCESS;
646 path = s_path->m_name;
647 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
648 memcpy(ad_entry( adp, ADEID_NAME ), path,
649 ad_getentrylen( adp, ADEID_NAME ));
650 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
651 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
657 if (vol->v_flags & AFPVOL_DROPBOX) {
658 retvalue = matchfile2dirperms(upath, vol, did);
660 #endif /* DROPKLUDGE */
662 setvoltime(obj, vol );
665 LOG(log_info, logtype_afpd, "end afp_createfile");
671 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
674 int ibuflen, *rbuflen;
680 u_int16_t vid, bitmap;
683 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
689 memcpy(&vid, ibuf, sizeof( vid ));
690 ibuf += sizeof( vid );
691 if (NULL == ( vol = getvolbyvid( vid )) ) {
692 return( AFPERR_PARAM );
695 if (vol->v_flags & AFPVOL_RO)
698 memcpy(&did, ibuf, sizeof( did ));
699 ibuf += sizeof( did );
700 if (NULL == ( dir = dirlookup( vol, did )) ) {
701 return afp_errno; /* was AFPERR_NOOBJ */
704 memcpy(&bitmap, ibuf, sizeof( bitmap ));
705 bitmap = ntohs( bitmap );
706 ibuf += sizeof( bitmap );
708 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
709 return get_afp_errno(AFPERR_PARAM);
712 if (path_isadir(s_path)) {
713 return( AFPERR_BADTYPE ); /* it's a directory */
716 if ( s_path->st_errno != 0 ) {
717 return( AFPERR_NOOBJ );
720 if ((u_long)ibuf & 1 ) {
724 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
725 setvoltime(obj, vol );
729 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
736 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
739 extern struct path Cur_Path;
741 int setfilparams(struct vol *vol,
742 struct path *path, u_int16_t bitmap, char *buf )
744 struct adouble ad, *adp;
747 int bit = 0, isad = 1, err = AFP_OK;
749 u_char achar, *fdType, xyy[4];
750 u_int16_t ashort, bshort;
754 int change_mdate = 0;
755 int change_parent_mdate = 0;
761 LOG(log_info, logtype_afpd, "begin setfilparams:");
764 upath = path->u_name;
765 if ((of = of_findname(path))) {
768 memset(&ad, 0, sizeof(ad));
772 if (check_access(upath, OPENACC_WR ) < 0) {
773 return AFPERR_ACCESS;
776 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
777 O_RDWR|O_CREAT, 0666, adp) < 0) {
778 /* for some things, we don't need an adouble header */
779 if (bitmap & ~(1<<FILPBIT_MDATE)) {
780 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
783 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
784 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
785 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
786 ad_getentrylen( adp, ADEID_NAME ));
789 while ( bitmap != 0 ) {
790 while (( bitmap & 1 ) == 0 ) {
798 memcpy(&ashort, buf, sizeof( ashort ));
799 ad_getattr(adp, &bshort);
800 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
801 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
805 if ((ashort & htons(ATTRBIT_INVISIBLE)))
806 change_parent_mdate = 1;
807 ad_setattr(adp, bshort);
808 buf += sizeof( ashort );
813 memcpy(&aint, buf, sizeof(aint));
814 ad_setdate(adp, AD_DATE_CREATE, aint);
815 buf += sizeof( aint );
819 memcpy(&newdate, buf, sizeof( newdate ));
820 buf += sizeof( newdate );
825 memcpy(&aint, buf, sizeof(aint));
826 ad_setdate(adp, AD_DATE_BACKUP, aint);
827 buf += sizeof( aint );
833 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
835 ((em = getextmap( path->m_name )) &&
836 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
837 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
838 || ((em = getdefextmap()) &&
839 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
840 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
842 memcpy(buf, ufinderi, 8 );
845 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
849 /* Client needs to set the ProDOS file info for this file.
850 Use a defined string for TEXT to support crlf
851 translations and convert all else into pXYY per Inside
852 Appletalk. Always set the creator as "pdos". Changes
853 from original by Marsha Jackson. */
854 case FILPBIT_PDINFO :
855 if (afp_version < 30) { /* else it's UTF8 name */
858 /* Keep special case to support crlf translations */
859 if ((unsigned int) achar == 0x04) {
860 fdType = (u_char *)"TEXT";
863 xyy[0] = ( u_char ) 'p';
869 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
870 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
876 goto setfilparam_done;
884 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
885 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
889 ad_setdate(adp, AD_DATE_MODIFY, newdate);
890 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
895 ad_flush( adp, ADFLAGS_HF );
896 ad_close( adp, ADFLAGS_HF );
900 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
901 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
902 bitmap = 1<<FILPBIT_MDATE;
903 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
907 LOG(log_info, logtype_afpd, "end setfilparams:");
913 * renamefile and copyfile take the old and new unix pathnames
914 * and the new mac name.
916 * src the source path
917 * dst the dest filename in current dir
918 * newname the dest mac name
919 * adp adouble struct of src file, if open, or & zeroed one
922 int renamefile(src, dst, newname, noadouble, adp )
923 char *src, *dst, *newname;
927 char adsrc[ MAXPATHLEN + 1];
932 LOG(log_info, logtype_afpd, "begin renamefile:");
935 if ( unix_rename( src, dst ) < 0 ) {
938 return( AFPERR_NOOBJ );
941 return( AFPERR_ACCESS );
944 case EXDEV : /* Cross device move -- try copy */
945 /* NOTE: with open file it's an error because after the copy we will
946 * get two files, it's fixable for our process (eg reopen the new file, get the
947 * locks, and so on. But it doesn't solve the case with a second process
949 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
950 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
951 return AFPERR_OLOCK; /* little lie */
953 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
954 /* on error copyfile delete dest */
957 return deletefile(NULL, src, 0);
959 return( AFPERR_PARAM );
963 strcpy( adsrc, ad_path( src, 0 ));
965 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
970 if (errno == ENOENT) {
973 if (stat(adsrc, &st)) /* source has no ressource fork, */
976 /* We are here because :
977 * -there's no dest folder.
978 * -there's no .AppleDouble in the dest folder.
979 * if we use the struct adouble passed in parameter it will not
980 * create .AppleDouble if the file is already opened, so we
981 * use a diff one, it's not a pb,ie it's not the same file, yet.
983 memset(&ad, 0, sizeof(ad));
984 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
985 ad_close(&ad, ADFLAGS_HF);
986 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
991 else { /* it's something else, bail out */
995 /* try to undo the data fork rename,
996 * we know we are on the same device
999 unix_rename( dst, src );
1000 /* return the first error */
1003 return AFPERR_NOOBJ;
1006 return AFPERR_ACCESS ;
1008 return AFPERR_VLOCK;
1010 return AFPERR_PARAM ;
1015 /* don't care if we can't open the newly renamed ressource fork
1017 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1018 len = strlen( newname );
1019 ad_setentrylen( adp, ADEID_NAME, len );
1020 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1021 ad_flush( adp, ADFLAGS_HF );
1022 ad_close( adp, ADFLAGS_HF );
1025 LOG(log_info, logtype_afpd, "end renamefile:");
1031 int copy_path_name(char *newname, char *ibuf)
1038 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1044 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1045 strncpy( newname, ibuf, plen );
1046 newname[ plen ] = '\0';
1047 if (strlen(newname) != plen) {
1048 /* there's \0 in newname, e.g. it's a pathname not
1056 memcpy(&hint, ibuf, sizeof(hint));
1057 ibuf += sizeof(hint);
1059 memcpy(&len16, ibuf, sizeof(len16));
1060 ibuf += sizeof(len16);
1061 plen = ntohs(len16);
1064 if (plen > AFPOBJ_TMPSIZ) {
1067 strncpy( newname, ibuf, plen );
1068 newname[ plen ] = '\0';
1069 if (strlen(newname) != plen) {
1078 /* -----------------------------------
1080 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1083 int ibuflen, *rbuflen;
1087 char *newname, *p, *upath;
1088 struct path *s_path;
1089 u_int32_t sdid, ddid;
1090 int err, retvalue = AFP_OK;
1091 u_int16_t svid, dvid;
1094 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1100 memcpy(&svid, ibuf, sizeof( svid ));
1101 ibuf += sizeof( svid );
1102 if (NULL == ( vol = getvolbyvid( svid )) ) {
1103 return( AFPERR_PARAM );
1106 memcpy(&sdid, ibuf, sizeof( sdid ));
1107 ibuf += sizeof( sdid );
1108 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1112 memcpy(&dvid, ibuf, sizeof( dvid ));
1113 ibuf += sizeof( dvid );
1114 memcpy(&ddid, ibuf, sizeof( ddid ));
1115 ibuf += sizeof( ddid );
1117 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1118 return get_afp_errno(AFPERR_PARAM);
1120 if ( path_isadir(s_path) ) {
1121 return( AFPERR_BADTYPE );
1124 /* don't allow copies when the file is open.
1125 * XXX: the spec only calls for read/deny write access.
1126 * however, copyfile doesn't have any of that info,
1127 * and locks need to stay coherent. as a result,
1128 * we just balk if the file is opened already. */
1130 newname = obj->newtmp;
1131 strcpy( newname, s_path->m_name );
1133 if (of_findname(s_path))
1134 return AFPERR_DENYCONF;
1136 p = ctoupath( vol, curdir, newname );
1138 return AFPERR_PARAM;
1142 /* FIXME svid != dvid && dvid's user can't read svid */
1144 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1145 return( AFPERR_PARAM );
1148 if (vol->v_flags & AFPVOL_RO)
1149 return AFPERR_VLOCK;
1151 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1155 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1156 return get_afp_errno(AFPERR_NOOBJ);
1158 if ( *s_path->m_name != '\0' ) {
1160 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1162 path_error(s_path, AFPERR_PARAM);
1165 /* one of the handful of places that knows about the path type */
1166 if (copy_path_name(newname, ibuf) < 0) {
1167 return( AFPERR_PARAM );
1170 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1171 return( AFPERR_PARAM );
1173 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1179 if (vol->v_flags & AFPVOL_DROPBOX) {
1180 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1182 #endif /* DROPKLUDGE */
1184 setvoltime(obj, vol );
1187 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1194 static __inline__ int copy_all(const int dfd, const void *buf,
1200 LOG(log_info, logtype_afpd, "begin copy_all:");
1203 while (buflen > 0) {
1204 if ((cc = write(dfd, buf, buflen)) < 0) {
1211 return AFPERR_DFULL;
1213 return AFPERR_VLOCK;
1215 return AFPERR_PARAM;
1222 LOG(log_info, logtype_afpd, "end copy_all:");
1228 /* -------------------------- */
1229 static int copy_fd(int dfd, int sfd)
1235 #ifdef SENDFILE_FLAVOR_LINUX
1238 if (fstat(sfd, &st) == 0) {
1239 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1241 case EINVAL: /* there's no guarantee that all fs support sendfile */
1246 return AFPERR_DFULL;
1248 return AFPERR_VLOCK;
1250 return AFPERR_PARAM;
1257 #endif /* SENDFILE_FLAVOR_LINUX */
1260 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1267 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1273 /* ----------------------------------
1274 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1275 * because we are doing it elsewhere.
1277 int copyfile(src, dst, newname, noadouble )
1278 char *src, *dst, *newname;
1279 const int noadouble;
1281 struct adouble ads, add;
1282 int len, err = AFP_OK;
1286 LOG(log_info, logtype_afpd, "begin copyfile:");
1289 memset(&ads, 0, sizeof(ads));
1290 memset(&add, 0, sizeof(add));
1291 adflags = ADFLAGS_DF;
1293 adflags |= ADFLAGS_HF;
1296 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1299 return( AFPERR_NOOBJ );
1301 return( AFPERR_ACCESS );
1303 return( AFPERR_PARAM );
1306 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1307 ad_close( &ads, adflags );
1308 if (EEXIST != (err = errno)) {
1309 deletefile(NULL, dst, 0);
1313 return AFPERR_EXIST;
1315 return( AFPERR_NOOBJ );
1317 return( AFPERR_ACCESS );
1319 return AFPERR_VLOCK;
1321 return( AFPERR_PARAM );
1324 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1325 /* copy the data fork */
1326 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1330 len = strlen( newname );
1331 ad_setentrylen( &add, ADEID_NAME, len );
1332 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1335 ad_close( &ads, adflags );
1336 ad_flush( &add, adflags );
1337 if (ad_close( &add, adflags ) <0) {
1340 if (err != AFP_OK) {
1341 deletefile(NULL, dst, 0);
1344 return( AFPERR_NOOBJ );
1346 return( AFPERR_ACCESS );
1348 return( AFPERR_PARAM );
1353 LOG(log_info, logtype_afpd, "end copyfile:");
1360 /* -----------------------------------
1361 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1362 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1364 when deletefile is called we don't have lock on it, file is closed (for us)
1365 untrue if called by renamefile
1367 ad_open always try to open file RDWR first and ad_lock takes care of
1368 WRITE lock on read only file.
1370 int deletefile( vol, file, checkAttrib )
1376 int adflags, err = AFP_OK;
1379 LOG(log_info, logtype_afpd, "begin deletefile:");
1382 /* try to open both forks at once */
1383 adflags = ADFLAGS_DF|ADFLAGS_HF;
1385 memset(&ad, 0, sizeof(ad));
1386 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1389 if (adflags == ADFLAGS_DF)
1390 return AFPERR_NOOBJ;
1392 /* that failed. now try to open just the data fork */
1393 adflags = ADFLAGS_DF;
1397 return AFPERR_ACCESS;
1399 return AFPERR_VLOCK;
1401 return( AFPERR_PARAM );
1404 break; /* from the while */
1407 * Does kFPDeleteInhibitBit (bit 8) set?
1409 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1412 ad_getattr(&ad, &bshort);
1413 if ((bshort & htons(ATTRBIT_NODELETE))) {
1414 ad_close( &ad, adflags );
1415 return(AFPERR_OLOCK);
1419 if ((adflags & ADFLAGS_HF) ) {
1420 /* FIXME we have a pb here because we want to know if a file is open
1421 * there's a 'priority inversion' if you can't open the ressource fork RW
1422 * you can delete it if it's open because you can't get a write lock.
1424 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1427 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1429 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1430 ad_close( &ad, adflags );
1431 return( AFPERR_BUSY );
1435 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1438 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1439 !(err = netatalk_unlink( file )) ) {
1440 #ifdef CNID_DB /* get rid of entry */
1442 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1444 cnid_delete(vol->v_db, id);
1446 #endif /* CNID_DB */
1449 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1452 LOG(log_info, logtype_afpd, "end deletefile:");
1458 /* ------------------------------------ */
1460 /* return a file id */
1461 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1464 int ibuflen, *rbuflen;
1473 struct path *s_path;
1476 LOG(log_info, logtype_afpd, "begin afp_createid:");
1483 memcpy(&vid, ibuf, sizeof(vid));
1484 ibuf += sizeof(vid);
1486 if (NULL == ( vol = getvolbyvid( vid )) ) {
1487 return( AFPERR_PARAM);
1490 if (vol->v_db == NULL) {
1494 if (vol->v_flags & AFPVOL_RO)
1495 return AFPERR_VLOCK;
1497 memcpy(&did, ibuf, sizeof( did ));
1498 ibuf += sizeof(did);
1500 if (NULL == ( dir = dirlookup( vol, did )) ) {
1501 return afp_errno; /* was AFPERR_PARAM */
1504 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1505 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1508 if ( path_isadir(s_path) ) {
1509 return( AFPERR_BADTYPE );
1512 upath = s_path->u_name;
1513 switch (s_path->st_errno) {
1515 break; /* success */
1518 return AFPERR_ACCESS;
1520 return AFPERR_NOOBJ;
1522 return AFPERR_PARAM;
1525 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1526 memcpy(rbuf, &id, sizeof(id));
1527 *rbuflen = sizeof(id);
1528 return AFPERR_EXISTID;
1531 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1532 memcpy(rbuf, &id, sizeof(id));
1533 *rbuflen = sizeof(id);
1538 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1543 /* ------------------------------
1544 resolve a file id */
1545 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1548 int ibuflen, *rbuflen;
1556 u_int16_t vid, bitmap;
1558 static char buffer[12 + MAXPATHLEN + 1];
1559 int len = 12 + MAXPATHLEN + 1;
1562 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1568 memcpy(&vid, ibuf, sizeof(vid));
1569 ibuf += sizeof(vid);
1571 if (NULL == ( vol = getvolbyvid( vid )) ) {
1572 return( AFPERR_PARAM);
1575 if (vol->v_db == NULL) {
1579 memcpy(&id, ibuf, sizeof( id ));
1582 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1583 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1586 if (NULL == ( dir = dirlookup( vol, id )) ) {
1587 return AFPERR_NOID; /* idem AFPERR_PARAM */
1589 path.u_name = upath;
1590 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1594 return AFPERR_ACCESS;
1598 return AFPERR_PARAM;
1601 /* directories are bad */
1602 if (S_ISDIR(path.st.st_mode))
1603 return AFPERR_BADTYPE;
1605 memcpy(&bitmap, ibuf, sizeof(bitmap));
1606 bitmap = ntohs( bitmap );
1607 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1610 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1611 rbuf + sizeof(bitmap), &buflen))) {
1614 *rbuflen = buflen + sizeof(bitmap);
1615 memcpy(rbuf, ibuf, sizeof(bitmap));
1618 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1624 /* ------------------------------ */
1625 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1628 int ibuflen, *rbuflen;
1638 static char buffer[12 + MAXPATHLEN + 1];
1639 int len = 12 + MAXPATHLEN + 1;
1642 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1648 memcpy(&vid, ibuf, sizeof(vid));
1649 ibuf += sizeof(vid);
1651 if (NULL == ( vol = getvolbyvid( vid )) ) {
1652 return( AFPERR_PARAM);
1655 if (vol->v_db == NULL) {
1659 if (vol->v_flags & AFPVOL_RO)
1660 return AFPERR_VLOCK;
1662 memcpy(&id, ibuf, sizeof( id ));
1666 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1670 if (NULL == ( dir = dirlookup( vol, id )) ) {
1671 return( AFPERR_PARAM );
1675 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1679 return AFPERR_ACCESS;
1681 /* still try to delete the id */
1685 return AFPERR_PARAM;
1688 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1689 return AFPERR_BADTYPE;
1691 if (cnid_delete(vol->v_db, fileid)) {
1694 return AFPERR_VLOCK;
1697 return AFPERR_ACCESS;
1699 return AFPERR_PARAM;
1704 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1709 #endif /* CNID_DB */
1711 #define APPLETEMP ".AppleTempXXXXXX"
1713 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1716 int ibuflen, *rbuflen;
1718 struct stat srcst, destst;
1720 struct dir *dir, *sdir;
1721 char *spath, temp[17], *p;
1722 char *supath, *upath;
1727 struct adouble *adsp;
1728 struct adouble *addp;
1735 #endif /* CNID_DB */
1740 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1746 memcpy(&vid, ibuf, sizeof(vid));
1747 ibuf += sizeof(vid);
1749 if (NULL == ( vol = getvolbyvid( vid )) ) {
1750 return( AFPERR_PARAM);
1753 if (vol->v_flags & AFPVOL_RO)
1754 return AFPERR_VLOCK;
1756 /* source and destination dids */
1757 memcpy(&sid, ibuf, sizeof(sid));
1758 ibuf += sizeof(sid);
1759 memcpy(&did, ibuf, sizeof(did));
1760 ibuf += sizeof(did);
1763 if (NULL == (dir = dirlookup( vol, sid )) ) {
1764 return afp_errno; /* was AFPERR_PARAM */
1767 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1768 return get_afp_errno(AFPERR_NOOBJ);
1771 if ( path_isadir(path) ) {
1772 return( AFPERR_BADTYPE ); /* it's a dir */
1775 upath = path->u_name;
1776 switch (path->st_errno) {
1783 return AFPERR_ACCESS;
1785 return AFPERR_PARAM;
1787 memset(&ads, 0, sizeof(ads));
1789 if ((s_of = of_findname(path))) {
1790 /* reuse struct adouble so it won't break locks */
1793 memcpy(&srcst, &path->st, sizeof(struct stat));
1794 /* save some stuff */
1796 spath = obj->oldtmp;
1797 supath = obj->newtmp;
1798 strcpy(spath, path->m_name);
1799 strcpy(supath, upath); /* this is for the cnid changing */
1800 p = absupath( vol, sdir, upath);
1802 /* pathname too long */
1803 return AFPERR_PARAM ;
1806 /* look for the source cnid. if it doesn't exist, don't worry about
1809 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1810 slen = strlen(supath));
1811 #endif /* CNID_DB */
1813 if (NULL == ( dir = dirlookup( vol, did )) ) {
1814 return afp_errno; /* was AFPERR_PARAM */
1817 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1818 return get_afp_errno(AFPERR_NOOBJ);
1821 if ( path_isadir(path) ) {
1822 return( AFPERR_BADTYPE );
1825 /* FPExchangeFiles is the only call that can return the SameObj
1827 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1828 return AFPERR_SAMEOBJ;
1830 switch (path->st_errno) {
1837 return AFPERR_ACCESS;
1839 return AFPERR_PARAM;
1841 memset(&add, 0, sizeof(add));
1843 if ((d_of = of_findname( path))) {
1844 /* reuse struct adouble so it won't break locks */
1847 memcpy(&destst, &path->st, sizeof(struct stat));
1849 /* they are not on the same device and at least one is open
1851 crossdev = (srcst.st_dev != destst.st_dev);
1852 if ((d_of || s_of) && crossdev)
1855 upath = path->u_name;
1857 /* look for destination id. */
1858 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1859 dlen = strlen(upath));
1860 #endif /* CNID_DB */
1862 /* construct a temp name.
1863 * NOTE: the temp file will be in the dest file's directory. it
1864 * will also be inaccessible from AFP. */
1865 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1869 /* now, quickly rename the file. we error if we can't. */
1870 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1871 goto err_exchangefile;
1872 of_rename(vol, s_of, sdir, spath, curdir, temp);
1874 /* rename destination to source */
1875 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1876 goto err_src_to_tmp;
1877 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1879 /* rename temp to destination */
1880 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1881 goto err_dest_to_src;
1882 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1885 /* id's need switching. src -> dest and dest -> src.
1886 * we need to re-stat() if it was a cross device copy.
1889 cnid_delete(vol->v_db, sid);
1892 cnid_delete(vol->v_db, did);
1894 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1895 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1897 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1898 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1903 err = AFPERR_ACCESS;
1908 goto err_temp_to_dest;
1910 #endif /* CNID_DB */
1913 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1919 /* all this stuff is so that we can unwind a failed operation
1924 /* rename dest to temp */
1925 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1926 of_rename(vol, s_of, curdir, upath, curdir, temp);
1929 /* rename source back to dest */
1930 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1931 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1934 /* rename temp back to source */
1935 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1936 of_rename(vol, s_of, curdir, temp, sdir, spath);