aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/export.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/export.c')
-rw-r--r--fs/nfsd/export.c289
1 files changed, 241 insertions, 48 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 79bd03b8bbf8..2d295dda4c1d 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -26,12 +26,15 @@
26#include <linux/mount.h> 26#include <linux/mount.h>
27#include <linux/hash.h> 27#include <linux/hash.h>
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/exportfs.h>
29 30
30#include <linux/sunrpc/svc.h> 31#include <linux/sunrpc/svc.h>
31#include <linux/nfsd/nfsd.h> 32#include <linux/nfsd/nfsd.h>
32#include <linux/nfsd/nfsfh.h> 33#include <linux/nfsd/nfsfh.h>
33#include <linux/nfsd/syscall.h> 34#include <linux/nfsd/syscall.h>
34#include <linux/lockd/bind.h> 35#include <linux/lockd/bind.h>
36#include <linux/sunrpc/msg_prot.h>
37#include <linux/sunrpc/gss_api.h>
35 38
36#define NFSDDBG_FACILITY NFSDDBG_EXPORT 39#define NFSDDBG_FACILITY NFSDDBG_EXPORT
37 40
@@ -451,8 +454,48 @@ out_free_all:
451 return err; 454 return err;
452} 455}
453 456
457static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
458{
459 int listsize, err;
460 struct exp_flavor_info *f;
461
462 err = get_int(mesg, &listsize);
463 if (err)
464 return err;
465 if (listsize < 0 || listsize > MAX_SECINFO_LIST)
466 return -EINVAL;
467
468 for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
469 err = get_int(mesg, &f->pseudoflavor);
470 if (err)
471 return err;
472 /*
473 * Just a quick sanity check; we could also try to check
474 * whether this pseudoflavor is supported, but at worst
475 * an unsupported pseudoflavor on the export would just
476 * be a pseudoflavor that won't match the flavor of any
477 * authenticated request. The administrator will
478 * probably discover the problem when someone fails to
479 * authenticate.
480 */
481 if (f->pseudoflavor < 0)
482 return -EINVAL;
483 err = get_int(mesg, &f->flags);
484 if (err)
485 return err;
486 /* Only some flags are allowed to differ between flavors: */
487 if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
488 return -EINVAL;
489 }
490 exp->ex_nflavors = listsize;
491 return 0;
492}
493
454#else /* CONFIG_NFSD_V4 */ 494#else /* CONFIG_NFSD_V4 */
455static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } 495static inline int
496fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
497static inline int
498secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
456#endif 499#endif
457 500
458static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) 501static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
@@ -476,6 +519,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
476 519
477 exp.ex_uuid = NULL; 520 exp.ex_uuid = NULL;
478 521
522 /* secinfo */
523 exp.ex_nflavors = 0;
524
479 if (mesg[mlen-1] != '\n') 525 if (mesg[mlen-1] != '\n')
480 return -EINVAL; 526 return -EINVAL;
481 mesg[mlen-1] = 0; 527 mesg[mlen-1] = 0;
@@ -553,7 +599,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
553 if (exp.ex_uuid == NULL) 599 if (exp.ex_uuid == NULL)
554 err = -ENOMEM; 600 err = -ENOMEM;
555 } 601 }
556 } else 602 } else if (strcmp(buf, "secinfo") == 0)
603 err = secinfo_parse(&mesg, buf, &exp);
604 else
557 /* quietly ignore unknown words and anything 605 /* quietly ignore unknown words and anything
558 * following. Newer user-space can try to set 606 * following. Newer user-space can try to set
559 * new values, then see what the result was. 607 * new values, then see what the result was.
@@ -593,6 +641,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
593 641
594static void exp_flags(struct seq_file *m, int flag, int fsid, 642static void exp_flags(struct seq_file *m, int flag, int fsid,
595 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); 643 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
644static void show_secinfo(struct seq_file *m, struct svc_export *exp);
596 645
597static int svc_export_show(struct seq_file *m, 646static int svc_export_show(struct seq_file *m,
598 struct cache_detail *cd, 647 struct cache_detail *cd,
@@ -622,6 +671,7 @@ static int svc_export_show(struct seq_file *m,
622 seq_printf(m, "%02x", exp->ex_uuid[i]); 671 seq_printf(m, "%02x", exp->ex_uuid[i]);
623 } 672 }
624 } 673 }
674 show_secinfo(m, exp);
625 } 675 }
626 seq_puts(m, ")\n"); 676 seq_puts(m, ")\n");
627 return 0; 677 return 0;
@@ -654,6 +704,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
654{ 704{
655 struct svc_export *new = container_of(cnew, struct svc_export, h); 705 struct svc_export *new = container_of(cnew, struct svc_export, h);
656 struct svc_export *item = container_of(citem, struct svc_export, h); 706 struct svc_export *item = container_of(citem, struct svc_export, h);
707 int i;
657 708
658 new->ex_flags = item->ex_flags; 709 new->ex_flags = item->ex_flags;
659 new->ex_anon_uid = item->ex_anon_uid; 710 new->ex_anon_uid = item->ex_anon_uid;
@@ -669,6 +720,10 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
669 item->ex_fslocs.locations_count = 0; 720 item->ex_fslocs.locations_count = 0;
670 new->ex_fslocs.migrated = item->ex_fslocs.migrated; 721 new->ex_fslocs.migrated = item->ex_fslocs.migrated;
671 item->ex_fslocs.migrated = 0; 722 item->ex_fslocs.migrated = 0;
723 new->ex_nflavors = item->ex_nflavors;
724 for (i = 0; i < MAX_SECINFO_LIST; i++) {
725 new->ex_flavors[i] = item->ex_flavors[i];
726 }
672} 727}
673 728
674static struct cache_head *svc_export_alloc(void) 729static struct cache_head *svc_export_alloc(void)
@@ -738,16 +793,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
738 int err; 793 int err;
739 794
740 if (!clp) 795 if (!clp)
741 return NULL; 796 return ERR_PTR(-ENOENT);
742 797
743 key.ek_client = clp; 798 key.ek_client = clp;
744 key.ek_fsidtype = fsid_type; 799 key.ek_fsidtype = fsid_type;
745 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 800 memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
746 801
747 ek = svc_expkey_lookup(&key); 802 ek = svc_expkey_lookup(&key);
748 if (ek != NULL) 803 if (ek == NULL)
749 if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) 804 return ERR_PTR(-ENOMEM);
750 ek = ERR_PTR(err); 805 err = cache_check(&svc_expkey_cache, &ek->h, reqp);
806 if (err)
807 return ERR_PTR(err);
751 return ek; 808 return ek;
752} 809}
753 810
@@ -808,30 +865,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
808 struct cache_req *reqp) 865 struct cache_req *reqp)
809{ 866{
810 struct svc_export *exp, key; 867 struct svc_export *exp, key;
868 int err;
811 869
812 if (!clp) 870 if (!clp)
813 return NULL; 871 return ERR_PTR(-ENOENT);
814 872
815 key.ex_client = clp; 873 key.ex_client = clp;
816 key.ex_mnt = mnt; 874 key.ex_mnt = mnt;
817 key.ex_dentry = dentry; 875 key.ex_dentry = dentry;
818 876
819 exp = svc_export_lookup(&key); 877 exp = svc_export_lookup(&key);
820 if (exp != NULL) { 878 if (exp == NULL)
821 int err; 879 return ERR_PTR(-ENOMEM);
822 880 err = cache_check(&svc_export_cache, &exp->h, reqp);
823 err = cache_check(&svc_export_cache, &exp->h, reqp); 881 if (err)
824 switch (err) { 882 return ERR_PTR(err);
825 case 0: break;
826 case -EAGAIN:
827 case -ETIMEDOUT:
828 exp = ERR_PTR(err);
829 break;
830 default:
831 exp = NULL;
832 }
833 }
834
835 return exp; 883 return exp;
836} 884}
837 885
@@ -847,7 +895,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
847 dget(dentry); 895 dget(dentry);
848 exp = exp_get_by_name(clp, mnt, dentry, reqp); 896 exp = exp_get_by_name(clp, mnt, dentry, reqp);
849 897
850 while (exp == NULL && !IS_ROOT(dentry)) { 898 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
851 struct dentry *parent; 899 struct dentry *parent;
852 900
853 parent = dget_parent(dentry); 901 parent = dget_parent(dentry);
@@ -900,7 +948,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
900 return; 948 return;
901 949
902 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); 950 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
903 if (ek && !IS_ERR(ek)) { 951 if (!IS_ERR(ek)) {
904 ek->h.expiry_time = get_seconds()-1; 952 ek->h.expiry_time = get_seconds()-1;
905 cache_put(&ek->h, &svc_expkey_cache); 953 cache_put(&ek->h, &svc_expkey_cache);
906 } 954 }
@@ -938,7 +986,7 @@ static void exp_unhash(struct svc_export *exp)
938 struct inode *inode = exp->ex_dentry->d_inode; 986 struct inode *inode = exp->ex_dentry->d_inode;
939 987
940 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); 988 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
941 if (ek && !IS_ERR(ek)) { 989 if (!IS_ERR(ek)) {
942 ek->h.expiry_time = get_seconds()-1; 990 ek->h.expiry_time = get_seconds()-1;
943 cache_put(&ek->h, &svc_expkey_cache); 991 cache_put(&ek->h, &svc_expkey_cache);
944 } 992 }
@@ -989,13 +1037,12 @@ exp_export(struct nfsctl_export *nxp)
989 1037
990 /* must make sure there won't be an ex_fsid clash */ 1038 /* must make sure there won't be an ex_fsid clash */
991 if ((nxp->ex_flags & NFSEXP_FSID) && 1039 if ((nxp->ex_flags & NFSEXP_FSID) &&
992 (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && 1040 (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
993 !IS_ERR(fsid_key) &&
994 fsid_key->ek_mnt && 1041 fsid_key->ek_mnt &&
995 (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) 1042 (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
996 goto finish; 1043 goto finish;
997 1044
998 if (exp) { 1045 if (!IS_ERR(exp)) {
999 /* just a flags/id/fsid update */ 1046 /* just a flags/id/fsid update */
1000 1047
1001 exp_fsid_unhash(exp); 1048 exp_fsid_unhash(exp);
@@ -1104,7 +1151,7 @@ exp_unexport(struct nfsctl_export *nxp)
1104 err = -EINVAL; 1151 err = -EINVAL;
1105 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); 1152 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
1106 path_release(&nd); 1153 path_release(&nd);
1107 if (!exp) 1154 if (IS_ERR(exp))
1108 goto out_domain; 1155 goto out_domain;
1109 1156
1110 exp_do_unexport(exp); 1157 exp_do_unexport(exp);
@@ -1149,10 +1196,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
1149 err = PTR_ERR(exp); 1196 err = PTR_ERR(exp);
1150 goto out; 1197 goto out;
1151 } 1198 }
1152 if (!exp) {
1153 dprintk("nfsd: exp_rootfh export not found.\n");
1154 goto out;
1155 }
1156 1199
1157 /* 1200 /*
1158 * fh must be initialized before calling fh_compose 1201 * fh must be initialized before calling fh_compose
@@ -1176,17 +1219,130 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
1176{ 1219{
1177 struct svc_export *exp; 1220 struct svc_export *exp;
1178 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); 1221 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
1179 if (!ek || IS_ERR(ek)) 1222 if (IS_ERR(ek))
1180 return ERR_PTR(PTR_ERR(ek)); 1223 return ERR_PTR(PTR_ERR(ek));
1181 1224
1182 exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); 1225 exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
1183 cache_put(&ek->h, &svc_expkey_cache); 1226 cache_put(&ek->h, &svc_expkey_cache);
1184 1227
1185 if (!exp || IS_ERR(exp)) 1228 if (IS_ERR(exp))
1186 return ERR_PTR(PTR_ERR(exp)); 1229 return ERR_PTR(PTR_ERR(exp));
1187 return exp; 1230 return exp;
1188} 1231}
1189 1232
1233__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
1234{
1235 struct exp_flavor_info *f;
1236 struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1237
1238 /* legacy gss-only clients are always OK: */
1239 if (exp->ex_client == rqstp->rq_gssclient)
1240 return 0;
1241 /* ip-address based client; check sec= export option: */
1242 for (f = exp->ex_flavors; f < end; f++) {
1243 if (f->pseudoflavor == rqstp->rq_flavor)
1244 return 0;
1245 }
1246 /* defaults in absence of sec= options: */
1247 if (exp->ex_nflavors == 0) {
1248 if (rqstp->rq_flavor == RPC_AUTH_NULL ||
1249 rqstp->rq_flavor == RPC_AUTH_UNIX)
1250 return 0;
1251 }
1252 return nfserr_wrongsec;
1253}
1254
1255/*
1256 * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
1257 * auth_unix client) if it's available and has secinfo information;
1258 * otherwise, will try to use rq_gssclient.
1259 *
1260 * Called from functions that handle requests; functions that do work on
1261 * behalf of mountd are passed a single client name to use, and should
1262 * use exp_get_by_name() or exp_find().
1263 */
1264struct svc_export *
1265rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
1266 struct dentry *dentry)
1267{
1268 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1269
1270 if (rqstp->rq_client == NULL)
1271 goto gss;
1272
1273 /* First try the auth_unix client: */
1274 exp = exp_get_by_name(rqstp->rq_client, mnt, dentry,
1275 &rqstp->rq_chandle);
1276 if (PTR_ERR(exp) == -ENOENT)
1277 goto gss;
1278 if (IS_ERR(exp))
1279 return exp;
1280 /* If it has secinfo, assume there are no gss/... clients */
1281 if (exp->ex_nflavors > 0)
1282 return exp;
1283gss:
1284 /* Otherwise, try falling back on gss client */
1285 if (rqstp->rq_gssclient == NULL)
1286 return exp;
1287 gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry,
1288 &rqstp->rq_chandle);
1289 if (PTR_ERR(gssexp) == -ENOENT)
1290 return exp;
1291 if (!IS_ERR(exp))
1292 exp_put(exp);
1293 return gssexp;
1294}
1295
1296struct svc_export *
1297rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
1298{
1299 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1300
1301 if (rqstp->rq_client == NULL)
1302 goto gss;
1303
1304 /* First try the auth_unix client: */
1305 exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
1306 if (PTR_ERR(exp) == -ENOENT)
1307 goto gss;
1308 if (IS_ERR(exp))
1309 return exp;
1310 /* If it has secinfo, assume there are no gss/... clients */
1311 if (exp->ex_nflavors > 0)
1312 return exp;
1313gss:
1314 /* Otherwise, try falling back on gss client */
1315 if (rqstp->rq_gssclient == NULL)
1316 return exp;
1317 gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
1318 &rqstp->rq_chandle);
1319 if (PTR_ERR(gssexp) == -ENOENT)
1320 return exp;
1321 if (!IS_ERR(exp))
1322 exp_put(exp);
1323 return gssexp;
1324}
1325
1326struct svc_export *
1327rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
1328 struct dentry *dentry)
1329{
1330 struct svc_export *exp;
1331
1332 dget(dentry);
1333 exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
1334
1335 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
1336 struct dentry *parent;
1337
1338 parent = dget_parent(dentry);
1339 dput(dentry);
1340 dentry = parent;
1341 exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
1342 }
1343 dput(dentry);
1344 return exp;
1345}
1190 1346
1191/* 1347/*
1192 * Called when we need the filehandle for the root of the pseudofs, 1348 * Called when we need the filehandle for the root of the pseudofs,
@@ -1194,8 +1350,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
1194 * export point with fsid==0 1350 * export point with fsid==0
1195 */ 1351 */
1196__be32 1352__be32
1197exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, 1353exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1198 struct cache_req *creq)
1199{ 1354{
1200 struct svc_export *exp; 1355 struct svc_export *exp;
1201 __be32 rv; 1356 __be32 rv;
@@ -1203,12 +1358,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
1203 1358
1204 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); 1359 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1205 1360
1206 exp = exp_find(clp, FSID_NUM, fsidv, creq); 1361 exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
1362 if (PTR_ERR(exp) == -ENOENT)
1363 return nfserr_perm;
1207 if (IS_ERR(exp)) 1364 if (IS_ERR(exp))
1208 return nfserrno(PTR_ERR(exp)); 1365 return nfserrno(PTR_ERR(exp));
1209 if (exp == NULL)
1210 return nfserr_perm;
1211 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); 1366 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
1367 if (rv)
1368 goto out;
1369 rv = check_nfsd_access(exp, rqstp);
1370out:
1212 exp_put(exp); 1371 exp_put(exp);
1213 return rv; 1372 return rv;
1214} 1373}
@@ -1296,28 +1455,62 @@ static struct flags {
1296 { 0, {"", ""}} 1455 { 0, {"", ""}}
1297}; 1456};
1298 1457
1299static void exp_flags(struct seq_file *m, int flag, int fsid, 1458static void show_expflags(struct seq_file *m, int flags, int mask)
1300 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1301{ 1459{
1302 int first = 0;
1303 struct flags *flg; 1460 struct flags *flg;
1461 int state, first = 0;
1304 1462
1305 for (flg = expflags; flg->flag; flg++) { 1463 for (flg = expflags; flg->flag; flg++) {
1306 int state = (flg->flag & flag)?0:1; 1464 if (flg->flag & ~mask)
1465 continue;
1466 state = (flg->flag & flags) ? 0 : 1;
1307 if (*flg->name[state]) 1467 if (*flg->name[state])
1308 seq_printf(m, "%s%s", first++?",":"", flg->name[state]); 1468 seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1309 } 1469 }
1470}
1471
1472static void show_secinfo_flags(struct seq_file *m, int flags)
1473{
1474 seq_printf(m, ",");
1475 show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1476}
1477
1478static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1479{
1480 struct exp_flavor_info *f;
1481 struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1482 int lastflags = 0, first = 0;
1483
1484 if (exp->ex_nflavors == 0)
1485 return;
1486 for (f = exp->ex_flavors; f < end; f++) {
1487 if (first || f->flags != lastflags) {
1488 if (!first)
1489 show_secinfo_flags(m, lastflags);
1490 seq_printf(m, ",sec=%d", f->pseudoflavor);
1491 lastflags = f->flags;
1492 } else {
1493 seq_printf(m, ":%d", f->pseudoflavor);
1494 }
1495 }
1496 show_secinfo_flags(m, lastflags);
1497}
1498
1499static void exp_flags(struct seq_file *m, int flag, int fsid,
1500 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1501{
1502 show_expflags(m, flag, NFSEXP_ALLFLAGS);
1310 if (flag & NFSEXP_FSID) 1503 if (flag & NFSEXP_FSID)
1311 seq_printf(m, "%sfsid=%d", first++?",":"", fsid); 1504 seq_printf(m, ",fsid=%d", fsid);
1312 if (anonu != (uid_t)-2 && anonu != (0x10000-2)) 1505 if (anonu != (uid_t)-2 && anonu != (0x10000-2))
1313 seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); 1506 seq_printf(m, ",anonuid=%u", anonu);
1314 if (anong != (gid_t)-2 && anong != (0x10000-2)) 1507 if (anong != (gid_t)-2 && anong != (0x10000-2))
1315 seq_printf(m, "%sanongid=%d", first++?",":"", anong); 1508 seq_printf(m, ",anongid=%u", anong);
1316 if (fsloc && fsloc->locations_count > 0) { 1509 if (fsloc && fsloc->locations_count > 0) {
1317 char *loctype = (fsloc->migrated) ? "refer" : "replicas"; 1510 char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1318 int i; 1511 int i;
1319 1512
1320 seq_printf(m, "%s%s=", first++?",":"", loctype); 1513 seq_printf(m, ",%s=", loctype);
1321 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); 1514 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1322 seq_putc(m, '@'); 1515 seq_putc(m, '@');
1323 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); 1516 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");