2 * $Id: file.c,v 1.89 2003-04-09 06:06:34 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 ) {
620 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
621 return ( AFPERR_NOOBJ );
623 return( AFPERR_EXIST );
625 return( AFPERR_ACCESS );
627 return( AFPERR_PARAM );
630 if ( ad_hfileno( adp ) == -1 ) {
631 /* on noadouble volumes, just creating the data fork is ok */
632 if (vol_noadouble(vol)) {
633 ad_close( adp, ADFLAGS_DF );
634 goto createfile_done;
636 /* FIXME with hard create on an existing file, we already
637 * corrupted the data file.
639 netatalk_unlink( upath );
640 ad_close( adp, ADFLAGS_DF );
641 return AFPERR_ACCESS;
644 path = s_path->m_name;
645 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
646 memcpy(ad_entry( adp, ADEID_NAME ), path,
647 ad_getentrylen( adp, ADEID_NAME ));
648 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
649 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
655 if (vol->v_flags & AFPVOL_DROPBOX) {
656 retvalue = matchfile2dirperms(upath, vol, did);
658 #endif /* DROPKLUDGE */
660 setvoltime(obj, vol );
663 LOG(log_info, logtype_afpd, "end afp_createfile");
669 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
672 int ibuflen, *rbuflen;
678 u_int16_t vid, bitmap;
681 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
687 memcpy(&vid, ibuf, sizeof( vid ));
688 ibuf += sizeof( vid );
689 if (NULL == ( vol = getvolbyvid( vid )) ) {
690 return( AFPERR_PARAM );
693 if (vol->v_flags & AFPVOL_RO)
696 memcpy(&did, ibuf, sizeof( did ));
697 ibuf += sizeof( did );
698 if (NULL == ( dir = dirlookup( vol, did )) ) {
699 return afp_errno; /* was AFPERR_NOOBJ */
702 memcpy(&bitmap, ibuf, sizeof( bitmap ));
703 bitmap = ntohs( bitmap );
704 ibuf += sizeof( bitmap );
706 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
707 return get_afp_errno(AFPERR_PARAM);
710 if (path_isadir(s_path)) {
711 return( AFPERR_BADTYPE ); /* it's a directory */
714 if ((u_long)ibuf & 1 ) {
718 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
719 setvoltime(obj, vol );
723 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
730 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
733 extern struct path Cur_Path;
735 int setfilparams(struct vol *vol,
736 struct path *path, u_int16_t bitmap, char *buf )
738 struct adouble ad, *adp;
741 int bit = 0, isad = 1, err = AFP_OK;
743 u_char achar, *fdType, xyy[4];
744 u_int16_t ashort, bshort;
748 int change_mdate = 0;
749 int change_parent_mdate = 0;
755 LOG(log_info, logtype_afpd, "begin setfilparams:");
758 upath = path->u_name;
759 if ((of = of_findname(path))) {
762 memset(&ad, 0, sizeof(ad));
766 if (check_access(upath, OPENACC_WR ) < 0) {
767 return AFPERR_ACCESS;
770 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
771 O_RDWR|O_CREAT, 0666, adp) < 0) {
772 /* for some things, we don't need an adouble header */
773 if (bitmap & ~(1<<FILPBIT_MDATE)) {
774 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
777 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
778 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
779 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
780 ad_getentrylen( adp, ADEID_NAME ));
783 while ( bitmap != 0 ) {
784 while (( bitmap & 1 ) == 0 ) {
792 memcpy(&ashort, buf, sizeof( ashort ));
793 ad_getattr(adp, &bshort);
794 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
795 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
799 if ((ashort & htons(ATTRBIT_INVISIBLE)))
800 change_parent_mdate = 1;
801 ad_setattr(adp, bshort);
802 buf += sizeof( ashort );
807 memcpy(&aint, buf, sizeof(aint));
808 ad_setdate(adp, AD_DATE_CREATE, aint);
809 buf += sizeof( aint );
813 memcpy(&newdate, buf, sizeof( newdate ));
814 buf += sizeof( newdate );
819 memcpy(&aint, buf, sizeof(aint));
820 ad_setdate(adp, AD_DATE_BACKUP, aint);
821 buf += sizeof( aint );
827 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
829 ((em = getextmap( path->m_name )) &&
830 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
831 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
832 || ((em = getdefextmap()) &&
833 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
834 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
836 memcpy(buf, ufinderi, 8 );
839 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
843 /* Client needs to set the ProDOS file info for this file.
844 Use a defined string for TEXT to support crlf
845 translations and convert all else into pXYY per Inside
846 Appletalk. Always set the creator as "pdos". Changes
847 from original by Marsha Jackson. */
848 case FILPBIT_PDINFO :
849 if (afp_version < 30) { /* else it's UTF8 name */
852 /* Keep special case to support crlf translations */
853 if ((unsigned int) achar == 0x04) {
854 fdType = (u_char *)"TEXT";
857 xyy[0] = ( u_char ) 'p';
863 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
864 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
870 goto setfilparam_done;
878 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
879 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
883 ad_setdate(adp, AD_DATE_MODIFY, newdate);
884 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
889 ad_flush( adp, ADFLAGS_HF );
890 ad_close( adp, ADFLAGS_HF );
894 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
895 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
896 bitmap = 1<<FILPBIT_MDATE;
897 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
901 LOG(log_info, logtype_afpd, "end setfilparams:");
907 * renamefile and copyfile take the old and new unix pathnames
908 * and the new mac name.
910 * src the source path
911 * dst the dest filename in current dir
912 * newname the dest mac name
913 * adp adouble struct of src file, if open, or & zeroed one
916 int renamefile(src, dst, newname, noadouble, adp )
917 char *src, *dst, *newname;
921 char adsrc[ MAXPATHLEN + 1];
926 LOG(log_info, logtype_afpd, "begin renamefile:");
929 if ( unix_rename( src, dst ) < 0 ) {
932 return( AFPERR_NOOBJ );
935 return( AFPERR_ACCESS );
938 case EXDEV : /* Cross device move -- try copy */
939 /* NOTE: with open file it's an error because after the copy we will
940 * get two files, it's fixable for our process (eg reopen the new file, get the
941 * locks, and so on. But it doesn't solve the case with a second process
943 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
944 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
945 return AFPERR_OLOCK; /* little lie */
947 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
948 /* on error copyfile delete dest */
951 return deletefile(NULL, src, 0);
953 return( AFPERR_PARAM );
957 strcpy( adsrc, ad_path( src, 0 ));
959 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
964 if (errno == ENOENT) {
967 if (stat(adsrc, &st)) /* source has no ressource fork, */
970 /* We are here because :
971 * -there's no dest folder.
972 * -there's no .AppleDouble in the dest folder.
973 * if we use the struct adouble passed in parameter it will not
974 * create .AppleDouble if the file is already opened, so we
975 * use a diff one, it's not a pb,ie it's not the same file, yet.
977 memset(&ad, 0, sizeof(ad));
978 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
979 ad_close(&ad, ADFLAGS_HF);
980 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
985 else { /* it's something else, bail out */
989 /* try to undo the data fork rename,
990 * we know we are on the same device
993 unix_rename( dst, src );
994 /* return the first error */
1000 return AFPERR_ACCESS ;
1002 return AFPERR_VLOCK;
1004 return AFPERR_PARAM ;
1009 /* don't care if we can't open the newly renamed ressource fork
1011 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1012 len = strlen( newname );
1013 ad_setentrylen( adp, ADEID_NAME, len );
1014 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1015 ad_flush( adp, ADFLAGS_HF );
1016 ad_close( adp, ADFLAGS_HF );
1019 LOG(log_info, logtype_afpd, "end renamefile:");
1025 int copy_path_name(char *newname, char *ibuf)
1032 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1038 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1039 strncpy( newname, ibuf, plen );
1040 newname[ plen ] = '\0';
1041 if (strlen(newname) != plen) {
1042 /* there's \0 in newname, e.g. it's a pathname not
1050 memcpy(&hint, ibuf, sizeof(hint));
1051 ibuf += sizeof(hint);
1053 memcpy(&len16, ibuf, sizeof(len16));
1054 ibuf += sizeof(len16);
1055 plen = ntohs(len16);
1057 strncpy( newname, ibuf, plen );
1058 newname[ plen ] = '\0';
1059 if (strlen(newname) != plen) {
1068 /* -----------------------------------
1070 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1073 int ibuflen, *rbuflen;
1077 char *newname, *p, *upath;
1078 struct path *s_path;
1079 u_int32_t sdid, ddid;
1080 int err, retvalue = AFP_OK;
1081 u_int16_t svid, dvid;
1084 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1090 memcpy(&svid, ibuf, sizeof( svid ));
1091 ibuf += sizeof( svid );
1092 if (NULL == ( vol = getvolbyvid( svid )) ) {
1093 return( AFPERR_PARAM );
1096 memcpy(&sdid, ibuf, sizeof( sdid ));
1097 ibuf += sizeof( sdid );
1098 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1102 memcpy(&dvid, ibuf, sizeof( dvid ));
1103 ibuf += sizeof( dvid );
1104 memcpy(&ddid, ibuf, sizeof( ddid ));
1105 ibuf += sizeof( ddid );
1107 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1108 return get_afp_errno(AFPERR_PARAM);
1110 if ( path_isadir(s_path) ) {
1111 return( AFPERR_BADTYPE );
1114 /* don't allow copies when the file is open.
1115 * XXX: the spec only calls for read/deny write access.
1116 * however, copyfile doesn't have any of that info,
1117 * and locks need to stay coherent. as a result,
1118 * we just balk if the file is opened already. */
1120 newname = obj->newtmp;
1121 strcpy( newname, s_path->m_name );
1123 if (of_findname(s_path))
1124 return AFPERR_DENYCONF;
1126 p = ctoupath( vol, curdir, newname );
1128 return AFPERR_PARAM;
1132 /* FIXME svid != dvid && dvid's user can't read svid */
1134 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1135 return( AFPERR_PARAM );
1138 if (vol->v_flags & AFPVOL_RO)
1139 return AFPERR_VLOCK;
1141 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1145 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1146 return get_afp_errno(AFPERR_NOOBJ);
1148 if ( *s_path->m_name != '\0' ) {
1149 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1152 /* one of the handful of places that knows about the path type */
1153 if (copy_path_name(newname, ibuf) < 0) {
1154 return( AFPERR_PARAM );
1157 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1158 return( AFPERR_PARAM );
1160 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1166 if (vol->v_flags & AFPVOL_DROPBOX) {
1167 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1169 #endif /* DROPKLUDGE */
1171 setvoltime(obj, vol );
1174 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1181 static __inline__ int copy_all(const int dfd, const void *buf,
1187 LOG(log_info, logtype_afpd, "begin copy_all:");
1190 while (buflen > 0) {
1191 if ((cc = write(dfd, buf, buflen)) < 0) {
1198 return AFPERR_DFULL;
1200 return AFPERR_VLOCK;
1202 return AFPERR_PARAM;
1209 LOG(log_info, logtype_afpd, "end copy_all:");
1215 /* -------------------------- */
1216 static int copy_fd(int dfd, int sfd)
1222 #ifdef SENDFILE_FLAVOR_LINUX
1225 if (fstat(sfd, &st) == 0) {
1226 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1228 case EINVAL: /* there's no guarantee that all fs support sendfile */
1233 return AFPERR_DFULL;
1235 return AFPERR_VLOCK;
1237 return AFPERR_PARAM;
1244 #endif /* SENDFILE_FLAVOR_LINUX */
1247 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1254 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1260 /* ----------------------------------
1261 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1262 * because we are doing it elsewhere.
1264 int copyfile(src, dst, newname, noadouble )
1265 char *src, *dst, *newname;
1266 const int noadouble;
1268 struct adouble ads, add;
1269 int len, err = AFP_OK;
1273 LOG(log_info, logtype_afpd, "begin copyfile:");
1276 memset(&ads, 0, sizeof(ads));
1277 memset(&add, 0, sizeof(add));
1278 adflags = ADFLAGS_DF;
1280 adflags |= ADFLAGS_HF;
1283 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1286 return( AFPERR_NOOBJ );
1288 return( AFPERR_ACCESS );
1290 return( AFPERR_PARAM );
1293 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1294 ad_close( &ads, adflags );
1295 if (EEXIST != (err = errno)) {
1296 deletefile(NULL, dst, 0);
1300 return AFPERR_EXIST;
1302 return( AFPERR_NOOBJ );
1304 return( AFPERR_ACCESS );
1306 return AFPERR_VLOCK;
1308 return( AFPERR_PARAM );
1311 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1312 /* copy the data fork */
1313 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1317 len = strlen( newname );
1318 ad_setentrylen( &add, ADEID_NAME, len );
1319 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1322 ad_close( &ads, adflags );
1323 ad_flush( &add, adflags );
1324 if (ad_close( &add, adflags ) <0) {
1327 if (err != AFP_OK) {
1328 deletefile(NULL, dst, 0);
1331 return( AFPERR_NOOBJ );
1333 return( AFPERR_ACCESS );
1335 return( AFPERR_PARAM );
1340 LOG(log_info, logtype_afpd, "end copyfile:");
1347 /* -----------------------------------
1348 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1349 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1351 when deletefile is called we don't have lock on it, file is closed (for us)
1352 untrue if called by renamefile
1354 ad_open always try to open file RDWR first and ad_lock takes care of
1355 WRITE lock on read only file.
1357 int deletefile( vol, file, checkAttrib )
1363 int adflags, err = AFP_OK;
1366 LOG(log_info, logtype_afpd, "begin deletefile:");
1369 /* try to open both forks at once */
1370 adflags = ADFLAGS_DF|ADFLAGS_HF;
1372 memset(&ad, 0, sizeof(ad));
1373 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1376 if (adflags == ADFLAGS_DF)
1377 return AFPERR_NOOBJ;
1379 /* that failed. now try to open just the data fork */
1380 adflags = ADFLAGS_DF;
1384 return AFPERR_ACCESS;
1386 return AFPERR_VLOCK;
1388 return( AFPERR_PARAM );
1391 break; /* from the while */
1394 * Does kFPDeleteInhibitBit (bit 8) set?
1396 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1399 ad_getattr(&ad, &bshort);
1400 if ((bshort & htons(ATTRBIT_NODELETE))) {
1401 ad_close( &ad, adflags );
1402 return(AFPERR_OLOCK);
1406 if ((adflags & ADFLAGS_HF) ) {
1407 /* FIXME we have a pb here because we want to know if a file is open
1408 * there's a 'priority inversion' if you can't open the ressource fork RW
1409 * you can delete it if it's open because you can't get a write lock.
1411 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1414 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1416 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1417 ad_close( &ad, adflags );
1418 return( AFPERR_BUSY );
1422 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1425 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1426 !(err = netatalk_unlink( file )) ) {
1427 #ifdef CNID_DB /* get rid of entry */
1429 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1431 cnid_delete(vol->v_db, id);
1433 #endif /* CNID_DB */
1436 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1439 LOG(log_info, logtype_afpd, "end deletefile:");
1445 /* ------------------------------------ */
1447 /* return a file id */
1448 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1451 int ibuflen, *rbuflen;
1460 struct path *s_path;
1463 LOG(log_info, logtype_afpd, "begin afp_createid:");
1470 memcpy(&vid, ibuf, sizeof(vid));
1471 ibuf += sizeof(vid);
1473 if (NULL == ( vol = getvolbyvid( vid )) ) {
1474 return( AFPERR_PARAM);
1477 if (vol->v_db == NULL) {
1481 if (vol->v_flags & AFPVOL_RO)
1482 return AFPERR_VLOCK;
1484 memcpy(&did, ibuf, sizeof( did ));
1485 ibuf += sizeof(did);
1487 if (NULL == ( dir = dirlookup( vol, did )) ) {
1488 return afp_errno; /* was AFPERR_PARAM */
1491 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1492 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1495 if ( path_isadir(s_path) ) {
1496 return( AFPERR_BADTYPE );
1499 upath = s_path->u_name;
1500 switch (s_path->st_errno) {
1502 break; /* success */
1505 return AFPERR_ACCESS;
1507 return AFPERR_NOOBJ;
1509 return AFPERR_PARAM;
1512 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1513 memcpy(rbuf, &id, sizeof(id));
1514 *rbuflen = sizeof(id);
1515 return AFPERR_EXISTID;
1518 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1519 memcpy(rbuf, &id, sizeof(id));
1520 *rbuflen = sizeof(id);
1525 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1530 /* ------------------------------
1531 resolve a file id */
1532 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1535 int ibuflen, *rbuflen;
1543 u_int16_t vid, bitmap;
1545 static char buffer[12 + MAXPATHLEN + 1];
1546 int len = 12 + MAXPATHLEN + 1;
1549 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1555 memcpy(&vid, ibuf, sizeof(vid));
1556 ibuf += sizeof(vid);
1558 if (NULL == ( vol = getvolbyvid( vid )) ) {
1559 return( AFPERR_PARAM);
1562 if (vol->v_db == NULL) {
1566 memcpy(&id, ibuf, sizeof( id ));
1569 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1570 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1573 if (NULL == ( dir = dirlookup( vol, id )) ) {
1574 return AFPERR_NOID; /* idem AFPERR_PARAM */
1576 path.u_name = upath;
1577 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1581 return AFPERR_ACCESS;
1585 return AFPERR_PARAM;
1588 /* directories are bad */
1589 if (S_ISDIR(path.st.st_mode))
1590 return AFPERR_BADTYPE;
1592 memcpy(&bitmap, ibuf, sizeof(bitmap));
1593 bitmap = ntohs( bitmap );
1594 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1597 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1598 rbuf + sizeof(bitmap), &buflen))) {
1601 *rbuflen = buflen + sizeof(bitmap);
1602 memcpy(rbuf, ibuf, sizeof(bitmap));
1605 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1611 /* ------------------------------ */
1612 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1615 int ibuflen, *rbuflen;
1625 static char buffer[12 + MAXPATHLEN + 1];
1626 int len = 12 + MAXPATHLEN + 1;
1629 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1635 memcpy(&vid, ibuf, sizeof(vid));
1636 ibuf += sizeof(vid);
1638 if (NULL == ( vol = getvolbyvid( vid )) ) {
1639 return( AFPERR_PARAM);
1642 if (vol->v_db == NULL) {
1646 if (vol->v_flags & AFPVOL_RO)
1647 return AFPERR_VLOCK;
1649 memcpy(&id, ibuf, sizeof( id ));
1653 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1657 if (NULL == ( dir = dirlookup( vol, id )) ) {
1658 return( AFPERR_PARAM );
1662 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1666 return AFPERR_ACCESS;
1668 /* still try to delete the id */
1672 return AFPERR_PARAM;
1675 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1676 return AFPERR_BADTYPE;
1678 if (cnid_delete(vol->v_db, fileid)) {
1681 return AFPERR_VLOCK;
1684 return AFPERR_ACCESS;
1686 return AFPERR_PARAM;
1691 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1696 #endif /* CNID_DB */
1698 #define APPLETEMP ".AppleTempXXXXXX"
1700 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1703 int ibuflen, *rbuflen;
1705 struct stat srcst, destst;
1707 struct dir *dir, *sdir;
1708 char *spath, temp[17], *p;
1709 char *supath, *upath;
1714 struct adouble *adsp;
1715 struct adouble *addp;
1722 #endif /* CNID_DB */
1727 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1733 memcpy(&vid, ibuf, sizeof(vid));
1734 ibuf += sizeof(vid);
1736 if (NULL == ( vol = getvolbyvid( vid )) ) {
1737 return( AFPERR_PARAM);
1740 if (vol->v_flags & AFPVOL_RO)
1741 return AFPERR_VLOCK;
1743 /* source and destination dids */
1744 memcpy(&sid, ibuf, sizeof(sid));
1745 ibuf += sizeof(sid);
1746 memcpy(&did, ibuf, sizeof(did));
1747 ibuf += sizeof(did);
1750 if (NULL == (dir = dirlookup( vol, sid )) ) {
1751 return afp_errno; /* was AFPERR_PARAM */
1754 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1755 return get_afp_errno(AFPERR_NOOBJ);
1758 if ( path_isadir(path) ) {
1759 return( AFPERR_BADTYPE ); /* it's a dir */
1762 upath = path->u_name;
1763 switch (path->st_errno) {
1770 return AFPERR_ACCESS;
1772 return AFPERR_PARAM;
1774 memset(&ads, 0, sizeof(ads));
1776 if ((s_of = of_findname(path))) {
1777 /* reuse struct adouble so it won't break locks */
1780 memcpy(&srcst, &path->st, sizeof(struct stat));
1781 /* save some stuff */
1783 spath = obj->oldtmp;
1784 supath = obj->newtmp;
1785 strcpy(spath, path->m_name);
1786 strcpy(supath, upath); /* this is for the cnid changing */
1787 p = absupath( vol, sdir, upath);
1789 /* pathname too long */
1790 return AFPERR_PARAM ;
1793 /* look for the source cnid. if it doesn't exist, don't worry about
1796 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1797 slen = strlen(supath));
1798 #endif /* CNID_DB */
1800 if (NULL == ( dir = dirlookup( vol, did )) ) {
1801 return afp_errno; /* was AFPERR_PARAM */
1804 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1805 return get_afp_errno(AFPERR_NOOBJ);
1808 if ( path_isadir(path) ) {
1809 return( AFPERR_BADTYPE );
1812 /* FPExchangeFiles is the only call that can return the SameObj
1814 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1815 return AFPERR_SAMEOBJ;
1817 switch (path->st_errno) {
1824 return AFPERR_ACCESS;
1826 return AFPERR_PARAM;
1828 memset(&add, 0, sizeof(add));
1830 if ((d_of = of_findname( path))) {
1831 /* reuse struct adouble so it won't break locks */
1834 memcpy(&destst, &path->st, sizeof(struct stat));
1836 /* they are not on the same device and at least one is open
1838 crossdev = (srcst.st_dev != destst.st_dev);
1839 if ((d_of || s_of) && crossdev)
1842 upath = path->u_name;
1844 /* look for destination id. */
1845 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1846 dlen = strlen(upath));
1847 #endif /* CNID_DB */
1849 /* construct a temp name.
1850 * NOTE: the temp file will be in the dest file's directory. it
1851 * will also be inaccessible from AFP. */
1852 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1856 /* now, quickly rename the file. we error if we can't. */
1857 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1858 goto err_exchangefile;
1859 of_rename(vol, s_of, sdir, spath, curdir, temp);
1861 /* rename destination to source */
1862 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1863 goto err_src_to_tmp;
1864 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1866 /* rename temp to destination */
1867 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1868 goto err_dest_to_src;
1869 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1872 /* id's need switching. src -> dest and dest -> src.
1873 * we need to re-stat() if it was a cross device copy.
1876 cnid_delete(vol->v_db, sid);
1879 cnid_delete(vol->v_db, did);
1881 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1882 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1884 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1885 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1890 err = AFPERR_ACCESS;
1895 goto err_temp_to_dest;
1897 #endif /* CNID_DB */
1900 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1906 /* all this stuff is so that we can unwind a failed operation
1911 /* rename dest to temp */
1912 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1913 of_rename(vol, s_of, curdir, upath, curdir, temp);
1916 /* rename source back to dest */
1917 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1918 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1921 /* rename temp back to source */
1922 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1923 of_rename(vol, s_of, curdir, temp, sdir, spath);