2 * $Id: file.c,v 1.25 2001-08-14 14:00:10 rufustfirefly 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 #endif /* HAVE_FCNTL_H */
26 #include <sys/syslog.h>
27 #include <sys/types.h>
29 #include <sys/param.h>
32 #include <netatalk/endian.h>
33 #include <atalk/adouble.h>
34 #include <atalk/afp.h>
35 #include <atalk/util.h>
37 #include <atalk/cnid.h>
39 #include "directory.h"
47 /* check for mtab DID code */
49 #include "parse_mtab.h"
55 #endif /* FORCE_UIDGID */
57 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
58 * field bytes subfield bytes
61 * ioFlFndrInfo 16 -> type 4 type field
62 * creator 4 creator field
63 * flags 2 finder flags:
65 * location 4 location in window
66 * folder 2 window that contains file
68 * ioFlXFndrInfo 16 -> iconID 2 icon id
70 * script 1 script system
72 * commentID 2 comment id
73 * putawayID 4 home directory id
76 const u_char ufinderi[] = {
77 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
78 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0
83 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
93 struct stat hst, lst, *lstp;
94 #else /* USE_LASTDID */
96 #endif /* USE_LASTDID */
97 struct adouble ad, *adp;
100 char *data, *nameoff = NULL, *upath;
101 int bit = 0, isad = 1, aint;
103 u_char achar, fdType[4];
106 syslog(LOG_INFO, "begin getfilparams:");
109 upath = mtoupath(vol, path);
110 if ((of = of_findname(vol, curdir, path))) {
113 memset(&ad, 0, sizeof(ad));
117 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
119 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
120 syslog( LOG_ERR, "getfilparams fstat: %m" );
124 while ( bitmap != 0 ) {
125 while (( bitmap & 1 ) == 0 ) {
133 ad_getattr(adp, &ashort);
134 } else if (*upath == '.') {
135 ashort = htons(ATTRBIT_INVISIBLE);
138 memcpy(data, &ashort, sizeof( ashort ));
139 data += sizeof( u_short );
143 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
144 data += sizeof( u_int32_t );
148 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
149 aint = AD_DATE_FROM_UNIX(st->st_mtime);
150 memcpy(data, &aint, sizeof( aint ));
151 data += sizeof( aint );
155 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
156 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
157 (hst.st_mtime < st->st_mtime)) {
158 aint = AD_DATE_FROM_UNIX(st->st_mtime);
161 aint = AD_DATE_FROM_UNIX(st->st_mtime);
163 memcpy(data, &aint, sizeof( int ));
164 data += sizeof( int );
168 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
169 aint = AD_DATE_START;
170 memcpy(data, &aint, sizeof( int ));
171 data += sizeof( int );
176 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
178 memcpy(data, ufinderi, 32);
179 if (*upath == '.') { /* make it invisible */
180 ashort = htons(FINDERINFO_INVISIBLE);
181 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
185 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
186 ufinderi, 8 ) == 0)) &&
187 (em = getextmap( path ))) {
188 memcpy(data, em->em_type, sizeof( em->em_type ));
189 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
196 data += sizeof( u_int16_t );
200 memset(data, 0, sizeof(u_int16_t));
201 data += sizeof( u_int16_t );
207 /* find out if we have a fixed did already */
208 aint = cnid_lookup(vol->v_db, st, dir->d_did, upath,
212 /* look in AD v2 header */
215 #if AD_VERSION > AD_VERSION1
217 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
218 #endif /* AD_VERSION > AD_VERSION1 */
221 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
222 strlen(upath), aint);
228 * What a fucking mess. First thing: DID and FNUMs are
229 * in the same space for purposes of enumerate (and several
230 * other wierd places). While we consider this Apple's bug,
231 * this is the work-around: In order to maintain constant and
232 * unique DIDs and FNUMs, we monotonically generate the DIDs
233 * during the session, and derive the FNUMs from the filesystem.
234 * Since the DIDs are small, we insure that the FNUMs are fairly
235 * large by setting thier high bits to the device number.
237 * AFS already does something very similar to this for the
238 * inode number, so we don't repeat the procedure.
241 * due to complaints over did's being non-persistent,
242 * here's the current hack to provide semi-persistent
244 * 1) we reserve the first bit for file ids.
245 * 2) the next 7 bits are for the device.
246 * 3) the remaining 24 bits are for the inode.
248 * both the inode and device information are actually hashes
249 * that are then truncated to the requisite bit length.
251 * it should be okay to use lstat to deal with symlinks.
254 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
255 #else /* USE_LASTDID */
256 lstp = lstat(upath, &lst) < 0 ? st : &lst;
258 aint = htonl( afpd_st_cnid ( lstp ) );
260 aint = htonl(CNID(lstp, 1));
261 #endif /* DID_MTAB */
262 #endif /* USE_LASTDID */
265 memcpy(data, &aint, sizeof( aint ));
266 data += sizeof( aint );
270 aint = htonl( st->st_size );
271 memcpy(data, &aint, sizeof( aint ));
272 data += sizeof( aint );
277 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
281 memcpy(data, &aint, sizeof( aint ));
282 data += sizeof( aint );
285 /* Current client needs ProDOS info block for this file.
286 Use simple heuristic and let the Mac "type" string tell
287 us what the PD file code should be. Everything gets a
288 subtype of 0x0000 unless the original value was hashed
289 to "pXYZ" when we created it. See IA, Ver 2.
291 case FILPBIT_PDINFO :
293 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
295 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
299 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
303 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
307 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
311 else if ( fdType[0] == 'p' ) {
313 ashort = (fdType[2] * 256) + fdType[3];
327 memcpy(data, &ashort, sizeof( ashort ));
328 data += sizeof( ashort );
329 memset(data, 0, sizeof( ashort ));
330 data += sizeof( ashort );
335 ad_close( adp, ADFLAGS_HF );
337 return( AFPERR_BITMAP );
343 ashort = htons( data - buf );
344 memcpy(nameoff, &ashort, sizeof( ashort ));
345 if ((aint = strlen( path )) > MACFILELEN)
348 memcpy(data, path, aint );
352 ad_close( adp, ADFLAGS_HF );
354 *buflen = data - buf;
357 syslog(LOG_INFO, "end getfilparams:");
363 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
366 int ibuflen, *rbuflen;
369 struct adouble ad, *adp;
374 int creatf, did, openf, retvalue = AFP_OK;
378 #endif /* FORCE_UIDGID */
381 syslog(LOG_INFO, "begin afp_createfile:");
386 creatf = (unsigned char) *ibuf++;
388 memcpy(&vid, ibuf, sizeof( vid ));
389 ibuf += sizeof( vid );
391 if (( vol = getvolbyvid( vid )) == NULL ) {
392 return( AFPERR_PARAM );
395 if (vol->v_flags & AFPVOL_RO)
398 memcpy(&did, ibuf, sizeof( did));
399 ibuf += sizeof( did );
401 if (( dir = dirsearch( vol, did )) == NULL ) {
402 return( AFPERR_NOOBJ );
405 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
406 return( AFPERR_NOOBJ );
409 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
410 strpbrk(path, MSWINDOWS_BADCHARS))
413 upath = mtoupath(vol, path);
415 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
418 if (!validupath(vol, upath))
421 if ((of = of_findname(vol, curdir, path))) {
424 memset(&ad, 0, sizeof(ad));
428 /* on a hard create, fail if file exists and is open */
429 if ((stat(upath, &st) == 0) && of)
431 openf = O_RDWR|O_CREAT|O_TRUNC;
433 openf = O_RDWR|O_CREAT|O_EXCL;
438 /* preserve current euid, egid */
439 save_uidgid ( uidgid );
441 /* perform all switching of users */
444 #endif /* FORCE_UIDGID */
446 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
447 openf, 0666, adp) < 0 ) {
451 /* bring everything back to old euid, egid */
452 restore_uidgid ( uidgid );
453 #endif /* FORCE_UIDGID */
454 return( AFPERR_EXIST );
457 /* bring everything back to old euid, egid */
458 restore_uidgid ( uidgid );
459 #endif /* FORCE_UIDGID */
460 return( AFPERR_ACCESS );
462 /* on noadouble volumes, just creating the data fork is ok */
463 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
464 goto createfile_done;
468 /* bring everything back to old euid, egid */
469 restore_uidgid ( uidgid );
470 #endif /* FORCE_UIDGID */
471 return( AFPERR_PARAM );
475 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
476 memcpy(ad_entry( adp, ADEID_NAME ), path,
477 ad_getentrylen( adp, ADEID_NAME ));
478 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
479 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
484 if (vol->v_flags & AFPVOL_DROPBOX) {
485 retvalue = matchfile2dirperms(upath, vol, did);
487 #endif /* DROPKLUDGE */
489 setvoltime(obj, vol );
492 syslog(LOG_INFO, "end afp_createfile");
496 /* bring everything back to old euid, egid */
497 restore_uidgid ( uidgid );
498 #endif /* FORCE_UIDGID */
503 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
506 int ibuflen, *rbuflen;
512 u_int16_t vid, bitmap;
515 syslog(LOG_INFO, "begin afp_setfilparams:");
521 memcpy(&vid, ibuf, sizeof( vid ));
522 ibuf += sizeof( vid );
523 if (( vol = getvolbyvid( vid )) == NULL ) {
524 return( AFPERR_PARAM );
527 if (vol->v_flags & AFPVOL_RO)
530 memcpy(&did, ibuf, sizeof( did ));
531 ibuf += sizeof( did );
532 if (( dir = dirsearch( vol, did )) == NULL ) {
533 return( AFPERR_NOOBJ );
536 memcpy(&bitmap, ibuf, sizeof( bitmap ));
537 bitmap = ntohs( bitmap );
538 ibuf += sizeof( bitmap );
540 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
541 return( AFPERR_NOOBJ );
544 if ((u_long)ibuf & 1 ) {
548 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
549 setvoltime(obj, vol );
553 syslog(LOG_INFO, "end afp_setfilparams:");
560 int setfilparams(vol, path, bitmap, buf )
565 struct adouble ad, *adp;
568 int bit = 0, isad = 1, err = AFP_OK;
570 u_char achar, *fdType, xyy[4];
571 u_int16_t ashort, bshort;
578 uidgid = malloc(sizeof(uidgidset));
579 #endif /* FORCE_UIDGID */
582 syslog(LOG_INFO, "begin setfilparams:");
585 upath = mtoupath(vol, path);
586 if ((of = of_findname(vol, curdir, path))) {
589 memset(&ad, 0, sizeof(ad));
594 save_uidgid ( uidgid );
596 #endif /* FORCE_UIDGID */
598 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
599 O_RDWR|O_CREAT, 0666, adp) < 0) {
600 /* for some things, we don't need an adouble header */
601 if (bitmap & ~(1<<FILPBIT_MDATE)) {
603 restore_uidgid ( uidgid );
604 #endif /* FORCE_UIDGID */
605 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
608 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
609 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
610 memcpy(ad_entry( adp, ADEID_NAME ), path,
611 ad_getentrylen( adp, ADEID_NAME ));
614 while ( bitmap != 0 ) {
615 while (( bitmap & 1 ) == 0 ) {
622 memcpy(&ashort, buf, sizeof( ashort ));
623 ad_getattr(adp, &bshort);
624 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
625 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
629 ad_setattr(adp, bshort);
630 buf += sizeof( ashort );
634 memcpy(&aint, buf, sizeof(aint));
635 ad_setdate(adp, AD_DATE_CREATE, aint);
636 buf += sizeof( aint );
640 memcpy(&aint, buf, sizeof( aint ));
642 ad_setdate(adp, AD_DATE_MODIFY, aint);
643 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
645 buf += sizeof( aint );
649 memcpy(&aint, buf, sizeof(aint));
650 ad_setdate(adp, AD_DATE_BACKUP, aint);
651 buf += sizeof( aint );
655 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
656 && (em = getextmap( path )) &&
657 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
658 (memcmp(buf + 4, em->em_creator,
659 sizeof( em->em_creator )) == 0)) {
660 memcpy(buf, ufinderi, 8 );
662 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
666 /* Client needs to set the ProDOS file info for this file.
667 Use defined strings for the simple cases, and convert
668 all else into pXYY per Inside Appletalk. Always set
669 the creator as "pdos". <shirsch@ibm.net> */
670 case FILPBIT_PDINFO :
673 memcpy(&ashort, buf, sizeof( ashort ));
674 ashort = ntohs( ashort );
677 switch ( (unsigned int) achar )
680 fdType = ( u_char *) "TEXT";
684 fdType = ( u_char *) "PSYS";
688 fdType = ( u_char *) "PS16";
692 fdType = ( u_char *) "BINA";
696 xyy[0] = ( u_char ) 'p';
698 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
699 xyy[3] = ( u_char ) ashort & 0xff;
704 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
705 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
711 goto setfilparam_done;
720 ad_flush( adp, ADFLAGS_HF );
721 ad_close( adp, ADFLAGS_HF );
724 restore_uidgid ( uidgid );
725 #endif /* FORCE_UIDGID */
730 syslog(LOG_INFO, "end setfilparams:");
737 * renamefile and copyfile take the old and new unix pathnames
738 * and the new mac name.
739 * NOTE: if we have to copy a file instead of renaming it, locks
742 int renamefile(src, dst, newname, noadouble )
743 char *src, *dst, *newname;
747 char adsrc[ MAXPATHLEN + 1];
751 * Note that this is only checking the existance of the data file,
752 * not the header file. The thinking is that if the data file doesn't
753 * exist, but the header file does, the right thing to do is remove
754 * the data file silently.
757 /* existence check moved to afp_moveandrename */
760 syslog (LOG_INFO, "begin renamefile:");
763 if ( rename( src, dst ) < 0 ) {
766 return( AFPERR_NOOBJ );
769 return( AFPERR_ACCESS );
772 case EXDEV : /* Cross device move -- try copy */
773 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
777 return deletefile( src );
779 return( AFPERR_PARAM );
783 strcpy( adsrc, ad_path( src, 0 ));
786 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
791 /* check for a source appledouble header. if it exists, make
792 * a dest appledouble directory and do the rename again. */
793 memset(&ad, 0, sizeof(ad));
794 if (rc || stat(adsrc, &st) ||
795 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
798 ad_close(&ad, ADFLAGS_HF);
802 return( AFPERR_ACCESS );
806 return( AFPERR_PARAM );
810 memset(&ad, 0, sizeof(ad));
811 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
814 return( AFPERR_NOOBJ );
816 return( AFPERR_ACCESS );
820 return( AFPERR_PARAM );
824 len = strlen( newname );
825 ad_setentrylen( &ad, ADEID_NAME, len );
826 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
827 ad_flush( &ad, ADFLAGS_HF );
828 ad_close( &ad, ADFLAGS_HF );
831 syslog (LOG_INFO, "end renamefile:");
837 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
840 int ibuflen, *rbuflen;
844 char *newname, *path, *p;
845 u_int32_t sdid, ddid;
846 int plen, err, retvalue = AFP_OK;
847 u_int16_t svid, dvid;
850 syslog (LOG_INFO, "begin afp_copyfile:");
856 memcpy(&svid, ibuf, sizeof( svid ));
857 ibuf += sizeof( svid );
858 if (( vol = getvolbyvid( svid )) == NULL ) {
859 return( AFPERR_PARAM );
862 memcpy(&sdid, ibuf, sizeof( sdid ));
863 ibuf += sizeof( sdid );
864 if (( dir = dirsearch( vol, sdid )) == NULL ) {
865 return( AFPERR_PARAM );
868 memcpy(&dvid, ibuf, sizeof( dvid ));
869 ibuf += sizeof( dvid );
870 memcpy(&ddid, ibuf, sizeof( ddid ));
871 ibuf += sizeof( ddid );
873 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
874 return( AFPERR_NOOBJ );
876 if ( *path == '\0' ) {
877 return( AFPERR_BADTYPE );
880 /* don't allow copies when the file is open.
881 * XXX: the spec only calls for read/deny write access.
882 * however, copyfile doesn't have any of that info,
883 * and locks need to stay coherent. as a result,
884 * we just balk if the file is opened already. */
885 if (of_findname(vol, curdir, path))
886 return AFPERR_DENYCONF;
888 newname = obj->newtmp;
889 strcpy( newname, path );
891 p = ctoupath( vol, curdir, newname );
893 if (( vol = getvolbyvid( dvid )) == NULL ) {
894 return( AFPERR_PARAM );
897 if (vol->v_flags & AFPVOL_RO)
900 if (( dir = dirsearch( vol, ddid )) == NULL ) {
901 return( AFPERR_PARAM );
904 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
905 return( AFPERR_NOOBJ );
907 if ( *path != '\0' ) {
908 return( AFPERR_BADTYPE );
911 /* one of the handful of places that knows about the path type */
912 if ( *ibuf++ != 2 ) {
913 return( AFPERR_PARAM );
915 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
916 strncpy( newname, ibuf, plen );
917 newname[ plen ] = '\0';
920 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
921 vol_noadouble(vol))) < 0 ) {
925 setvoltime(obj, vol );
928 if (vol->v_flags & AFPVOL_DROPBOX) {
929 retvalue=matchfile2dirperms(newname, vol, sdid);
931 #endif /* DROPKLUDGE */
934 syslog (LOG_INFO, "end afp_copyfile:");
941 static __inline__ int copy_all(const int dfd, const void *buf,
947 syslog(LOG_INFO, "begin copy_all:");
951 if ((cc = write(dfd, buf, buflen)) < 0) {
969 syslog(LOG_INFO, "end copy_all:");
975 /* XXX: this needs to use ad_open and ad_lock. so, we need to
976 * pass in vol and path */
977 int copyfile(src, dst, newname, noadouble )
978 char *src, *dst, *newname;
984 int sfd, dfd, len, err = AFP_OK;
988 syslog(LOG_INFO, "begin copyfile:");
992 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
995 break; /* just copy the data fork */
997 return( AFPERR_ACCESS );
999 return( AFPERR_PARAM );
1002 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1003 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1007 return( AFPERR_NOOBJ );
1009 return( AFPERR_ACCESS );
1011 return AFPERR_VLOCK;
1013 return( AFPERR_PARAM );
1018 #ifdef SENDFILE_FLAVOR_LINUX
1019 if (fstat(sfd, &st) == 0) {
1020 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1034 goto copyheader_done;
1036 #endif /* SENDFILE_FLAVOR_LINUX */
1038 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1045 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1053 unlink(ad_path(dst, ADFLAGS_HF));
1059 /* data fork copying */
1060 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1063 return( AFPERR_NOOBJ );
1065 return( AFPERR_ACCESS );
1067 return( AFPERR_PARAM );
1071 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1075 return( AFPERR_NOOBJ );
1077 return( AFPERR_ACCESS );
1079 return AFPERR_VLOCK;
1081 return( AFPERR_PARAM );
1085 #ifdef SENDFILE_FLAVOR_LINUX
1086 if (fstat(sfd, &st) == 0) {
1087 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1100 #endif /* SENDFILE_FLAVOR_LINUX */
1103 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1111 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1120 unlink(ad_path(dst, ADFLAGS_HF));
1126 memset(&ad, 0, sizeof(ad));
1127 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1131 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1133 return( AFPERR_ACCESS );
1135 return AFPERR_VLOCK;
1137 return( AFPERR_PARAM );
1141 len = strlen( newname );
1142 ad_setentrylen( &ad, ADEID_NAME, len );
1143 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1144 ad_flush( &ad, ADFLAGS_HF );
1145 ad_close( &ad, ADFLAGS_HF );
1149 syslog(LOG_INFO, "end copyfile:");
1156 int deletefile( file )
1160 int adflags, err = AFP_OK;
1161 int locktype = ADLOCK_WR;
1162 int openmode = O_RDWR;
1165 syslog(LOG_INFO, "begin deletefile:");
1170 * If can't open read/write then try again read-only. If it's open
1171 * read-only, we must do a read lock instead of a write lock.
1173 /* try to open both at once */
1174 adflags = ADFLAGS_DF|ADFLAGS_HF;
1175 memset(&ad, 0, sizeof(ad));
1176 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1179 adflags = ADFLAGS_DF;
1180 /* that failed. now try to open just the data fork */
1181 memset(&ad, 0, sizeof(ad));
1182 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1185 return AFPERR_NOOBJ;
1187 if(openmode == O_RDWR) {
1188 openmode = O_RDONLY;
1189 locktype = ADLOCK_RD;
1192 return AFPERR_ACCESS;
1195 return AFPERR_VLOCK;
1197 return AFPERR_PARAM;
1203 if(openmode == O_RDWR) {
1204 openmode = O_RDONLY;
1205 locktype = ADLOCK_RD;
1208 return AFPERR_ACCESS;
1211 return AFPERR_VLOCK;
1213 return( AFPERR_PARAM );
1216 break; /* from the while */
1219 if ((adflags & ADFLAGS_HF) &&
1220 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1221 ad_close( &ad, adflags );
1222 return( AFPERR_BUSY );
1225 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1230 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1234 err = AFPERR_ACCESS;
1247 if ( unlink( file ) < 0 ) {
1251 err = AFPERR_ACCESS;
1265 if (adflags & ADFLAGS_HF)
1266 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1267 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1268 ad_close( &ad, adflags );
1271 syslog(LOG_INFO, "end deletefile:");
1279 /* return a file id */
1280 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1283 int ibuflen, *rbuflen;
1295 syslog(LOG_INFO, "begin afp_createid:");
1301 memcpy(&vid, ibuf, sizeof(vid));
1302 ibuf += sizeof(vid);
1304 if (( vol = getvolbyvid( vid )) == NULL ) {
1305 return( AFPERR_PARAM);
1308 if (vol->v_flags & AFPVOL_RO)
1309 return AFPERR_VLOCK;
1311 memcpy(&did, ibuf, sizeof( did ));
1312 ibuf += sizeof(did);
1314 if (( dir = dirsearch( vol, did )) == NULL ) {
1315 return( AFPERR_PARAM );
1318 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1319 return( AFPERR_PARAM );
1322 if ( *path == '\0' ) {
1323 return( AFPERR_BADTYPE );
1326 upath = mtoupath(vol, path);
1327 if (stat(upath, &st) < 0) {
1331 return AFPERR_ACCESS;
1333 return AFPERR_NOOBJ;
1335 return AFPERR_PARAM;
1339 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1340 memcpy(rbuf, &id, sizeof(id));
1341 *rbuflen = sizeof(id);
1342 return AFPERR_EXISTID;
1345 #if AD_VERSION > AD_VERSION1
1346 memset(&ad, 0, sizeof(ad));
1347 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1350 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1351 ad_close(&ad, ADFLAGS_HF);
1354 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1355 memcpy(rbuf, &id, sizeof(id));
1356 *rbuflen = sizeof(id);
1359 #endif /* AD_VERSION > AD_VERSION1 */
1362 syslog(LOG_INFO, "ending afp_createid...:");
1367 return AFPERR_VLOCK;
1371 return AFPERR_ACCESS;
1374 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1375 return AFPERR_PARAM;
1379 /* resolve a file id */
1380 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1383 int ibuflen, *rbuflen;
1391 u_int16_t vid, bitmap;
1394 syslog(LOG_INFO, "begin afp_resolveid:");
1400 memcpy(&vid, ibuf, sizeof(vid));
1401 ibuf += sizeof(vid);
1403 if (( vol = getvolbyvid( vid )) == NULL ) {
1404 return( AFPERR_PARAM);
1407 memcpy(&id, ibuf, sizeof( id ));
1410 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1411 return AFPERR_BADID;
1414 if (( dir = dirsearch( vol, id )) == NULL ) {
1415 return( AFPERR_PARAM );
1418 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1422 return AFPERR_ACCESS;
1426 return AFPERR_PARAM;
1430 /* directories are bad */
1431 if (S_ISDIR(st.st_mode))
1432 return AFPERR_BADTYPE;
1434 memcpy(&bitmap, ibuf, sizeof(bitmap));
1435 bitmap = ntohs( bitmap );
1437 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1438 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1441 *rbuflen = buflen + sizeof(bitmap);
1442 memcpy(rbuf, ibuf, sizeof(bitmap));
1445 syslog(LOG_INFO, "end afp_resolveid:");
1451 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1454 int ibuflen, *rbuflen;
1465 syslog(LOG_INFO, "begin afp_deleteid:");
1471 memcpy(&vid, ibuf, sizeof(vid));
1472 ibuf += sizeof(vid);
1474 if (( vol = getvolbyvid( vid )) == NULL ) {
1475 return( AFPERR_PARAM);
1478 if (vol->v_flags & AFPVOL_RO)
1479 return AFPERR_VLOCK;
1481 memcpy(&id, ibuf, sizeof( id ));
1484 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1488 if (( dir = dirsearch( vol, id )) == NULL ) {
1489 return( AFPERR_PARAM );
1493 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1497 return AFPERR_ACCESS;
1499 /* still try to delete the id */
1503 return AFPERR_PARAM;
1507 /* directories are bad */
1508 if (S_ISDIR(st.st_mode))
1509 return AFPERR_BADTYPE;
1511 if (cnid_delete(vol->v_db, id)) {
1514 return AFPERR_VLOCK;
1517 return AFPERR_ACCESS;
1519 return AFPERR_PARAM;
1524 syslog(LOG_INFO, "end afp_deleteid:");
1529 #endif /* CNID_DB */
1531 #define APPLETEMP ".AppleTempXXXXXX"
1533 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1536 int ibuflen, *rbuflen;
1538 struct stat srcst, destst;
1540 struct dir *dir, *sdir;
1541 char *spath, temp[17], *path, *p;
1542 char *supath, *upath;
1546 #endif /* CNID_DB */
1551 syslog(LOG_INFO, "begin afp_exchangefiles:");
1557 memcpy(&vid, ibuf, sizeof(vid));
1558 ibuf += sizeof(vid);
1560 if (( vol = getvolbyvid( vid )) == NULL ) {
1561 return( AFPERR_PARAM);
1564 if (vol->v_flags & AFPVOL_RO)
1565 return AFPERR_VLOCK;
1567 /* source and destination dids */
1568 memcpy(&sid, ibuf, sizeof(sid));
1569 ibuf += sizeof(sid);
1570 memcpy(&did, ibuf, sizeof(did));
1571 ibuf += sizeof(did);
1574 if ((dir = dirsearch( vol, sid )) == NULL ) {
1575 return( AFPERR_PARAM );
1578 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1579 return( AFPERR_PARAM );
1582 if ( *path == '\0' ) {
1583 return( AFPERR_BADTYPE );
1586 upath = mtoupath(vol, path);
1587 if (stat(upath, &srcst) < 0) {
1593 return AFPERR_ACCESS;
1595 return AFPERR_PARAM;
1599 /* save some stuff */
1601 spath = obj->oldtmp;
1602 supath = obj->newtmp;
1603 strcpy(spath, path);
1604 strcpy(supath, upath); /* this is for the cnid changing */
1605 p = ctoupath( vol, sdir, spath);
1607 /* look for the source cnid. if it doesn't exist, don't worry about
1610 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1611 slen = strlen(supath));
1612 #endif /* CNID_DB */
1614 if (( dir = dirsearch( vol, did )) == NULL ) {
1615 return( AFPERR_PARAM );
1618 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1619 return( AFPERR_PARAM );
1622 if ( *path == '\0' ) {
1623 return( AFPERR_BADTYPE );
1626 /* FPExchangeFiles is the only call that can return the SameObj
1628 if ((curdir == sdir) && strcmp(spath, path) == 0)
1629 return AFPERR_SAMEOBJ;
1631 upath = mtoupath(vol, path);
1632 if (stat(upath, &destst) < 0) {
1638 return AFPERR_ACCESS;
1640 return AFPERR_PARAM;
1645 /* look for destination id. */
1646 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1647 dlen = strlen(upath));
1648 #endif /* CNID_DB */
1650 /* construct a temp name.
1651 * NOTE: the temp file will be in the dest file's directory. it
1652 * will also be inaccessible from AFP. */
1653 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1657 /* now, quickly rename the file. we error if we can't. */
1658 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1659 goto err_exchangefile;
1660 of_rename(vol, sdir, spath, curdir, temp);
1662 /* rename destination to source */
1663 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1664 goto err_src_to_tmp;
1665 of_rename(vol, curdir, path, sdir, spath);
1667 /* rename temp to destination */
1668 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1669 goto err_dest_to_src;
1670 of_rename(vol, curdir, temp, curdir, path);
1673 /* id's need switching. src -> dest and dest -> src. */
1674 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1675 upath, dlen) < 0)) {
1679 err = AFPERR_ACCESS;
1683 goto err_temp_to_dest;
1686 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1687 supath, slen) < 0)) {
1691 err = AFPERR_ACCESS;
1697 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1698 goto err_temp_to_dest;
1700 #endif /* CNID_DB */
1703 syslog(LOG_INFO, "ending afp_exchangefiles:");
1709 /* all this stuff is so that we can unwind a failed operation
1712 /* rename dest to temp */
1713 renamefile(upath, temp, temp, vol_noadouble(vol));
1714 of_rename(vol, curdir, upath, curdir, temp);
1717 /* rename source back to dest */
1718 renamefile(p, upath, path, vol_noadouble(vol));
1719 of_rename(vol, sdir, spath, curdir, path);
1722 /* rename temp back to source */
1723 renamefile(temp, p, spath, vol_noadouble(vol));
1724 of_rename(vol, curdir, temp, sdir, spath);