wstat.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "logfsos.h"
  2. #include "logfs.h"
  3. #include "fcall.h"
  4. #include "local.h"
  5. char *
  6. logfsserverwstat(LogfsServer *server, u32int fid, uchar *stat, ushort nstat)
  7. {
  8. Fid *f;
  9. uchar *p;
  10. ushort len;
  11. uchar *mep;
  12. Qid qid;
  13. u32int perm, mtime;
  14. uvlong length;
  15. char *name, *uname, *gname, *muname;
  16. int qiddonttouch, permdonttouch, mtimedonttouch, lengthdonttouch;
  17. Entry *e, *parent;
  18. LogMessage s;
  19. char *cuid, *ngid;
  20. Group *eg, *ng;
  21. char *cname;
  22. char *errmsg;
  23. char *nuid;
  24. if(server->trace > 1)
  25. print("logfsserverwstat(%ud, %ud)\n", fid, nstat);
  26. if(nstat < 49)
  27. return Eshortstat;
  28. p = stat;
  29. len = GBIT16(p); p += BIT16SZ;
  30. if(len + BIT16SZ != nstat)
  31. return Eshortstat;
  32. mep = p + len;
  33. p += BIT16SZ + BIT32SZ; /* skip type and dev */
  34. qid.type = *p++;
  35. qid.vers = GBIT32(p); p += BIT32SZ;
  36. qid.path = GBIT64(p); p += BIT64SZ;
  37. perm = GBIT32(p); p += BIT32SZ;
  38. p += BIT32SZ; /* skip atime */
  39. mtime = GBIT32(p); p += BIT32SZ;
  40. length = GBIT64(p); p+= BIT64SZ;
  41. if(!logfsgn(&p, mep, &name) || !logfsgn(&p, mep, &uname)
  42. || !logfsgn(&p, mep, &gname) || !logfsgn(&p, mep, &muname))
  43. return Eshortstat;
  44. if(p != mep)
  45. return Eshortstat;
  46. qiddonttouch = qid.type == (uchar)~0 && qid.vers == ~0 && qid.path == ~(uvlong)0;
  47. permdonttouch = perm == ~0;
  48. mtimedonttouch = mtime == ~0;
  49. lengthdonttouch = length == ~(uvlong)0;
  50. if(server->trace > 1) {
  51. int comma = 0;
  52. print("logfsserverwstat(");
  53. if(!qiddonttouch) {
  54. comma = 1;
  55. print("qid=0x%.2ux/%lud/%llud", qid.type, qid.vers, qid.path);
  56. }
  57. if(!permdonttouch) {
  58. if(comma)
  59. print(", ");
  60. print("perm=0%uo", perm);
  61. comma = 1;
  62. }
  63. if(!mtimedonttouch) {
  64. if(comma)
  65. print(", ");
  66. print("mtime=%ud", mtime);
  67. comma = 1;
  68. }
  69. if(!lengthdonttouch) {
  70. if(comma)
  71. print(", ");
  72. print("length=%llud", length);
  73. comma = 1;
  74. }
  75. if(name != nil) {
  76. if(comma)
  77. print(", ");
  78. print("name=%s", name);
  79. comma = 1;
  80. }
  81. if(uname != nil) {
  82. if(comma)
  83. print(", ");
  84. print("uid=%s", uname);
  85. comma = 1;
  86. }
  87. if(gname != nil) {
  88. if(comma)
  89. print(", ");
  90. print("gid=%s", gname);
  91. comma = 1;
  92. }
  93. if(muname != nil) {
  94. if(comma)
  95. print(", ");
  96. print("muname=%s", muname);
  97. comma = 1;
  98. }
  99. USED(comma);
  100. print(")\n");
  101. }
  102. f = logfsfidmapfindentry(server->fidmap, fid);
  103. if(f == nil)
  104. return logfsebadfid;
  105. e = f->entry;
  106. if(e->deadandgone)
  107. return Eio;
  108. parent = e->parent;
  109. if(name) {
  110. Entry *oe;
  111. if(parent == e)
  112. return Eperm;
  113. if(!logfsuserpermcheck(server, e->parent, f, DMWRITE))
  114. return Eperm;
  115. for(oe = parent->u.dir.list; oe; oe = oe->next) {
  116. if(oe == e)
  117. continue;
  118. if(strcmp(oe->name, name) == 0)
  119. return Eexist;
  120. }
  121. }
  122. if(!lengthdonttouch) {
  123. if(!logfsuserpermcheck(server, e, f, DMWRITE))
  124. return Eperm;
  125. if(e->qid.type & QTDIR) {
  126. if(length != 0)
  127. return Eperm;
  128. }else if(length != e->u.file.length){
  129. /*
  130. * TODO - truncate directory
  131. * TODO - truncate file
  132. */
  133. return "wstat -- can't change length";
  134. }
  135. }
  136. cuid = logfsisfindidfromname(server->is, f->uname);
  137. /* TODO - change entries to have a group pointer */
  138. eg = logfsisfindgroupfromid(server->is, e->uid);
  139. if(gname) {
  140. gname = logfsisustadd(server->is, gname);
  141. if(gname == nil)
  142. return Enomem;
  143. ngid = logfsisfindidfromname(server->is, gname);
  144. if(ngid == nil)
  145. return Eunknown;
  146. }
  147. else
  148. ngid = nil;
  149. if(uname) {
  150. uname = logfsisustadd(server->is, uname);
  151. if(uname == nil)
  152. return Enomem;
  153. nuid = logfsisfindidfromname(server->is, uname);
  154. if(nuid == nil)
  155. return Eunknown;
  156. }
  157. else
  158. nuid = nil;
  159. if(!permdonttouch || !mtimedonttouch) {
  160. /*
  161. * same permissions rules - change by owner, or by group leader
  162. */
  163. if((server->openflags & LogfsOpenFlagWstatAllow) == 0 &&
  164. e->uid != cuid && (eg == nil || !logfsisgroupuidisleader(server->is, eg, cuid)))
  165. return Eperm;
  166. }
  167. if(!permdonttouch){
  168. if((perm^e->perm) & DMDIR)
  169. return "wstat -- attempt to change directory";
  170. if(perm & ~(DMDIR|DMAPPEND|DMEXCL|0777))
  171. return Eperm;
  172. }
  173. if(gname) {
  174. int ok;
  175. ng = logfsisfindgroupfromid(server->is, ngid);
  176. ok = 0;
  177. if(e->uid == cuid && logfsisgroupuidismember(server->is, ng, e->uid))
  178. ok = 1;
  179. if(!ok && eg && logfsisgroupuidisleader(server->is, eg, cuid)
  180. && logfsisgroupuidisleader(server->is, ng, cuid))
  181. ok = 1;
  182. if(!ok && (server->openflags & LogfsOpenFlagWstatAllow) == 0)
  183. return Eperm;
  184. }
  185. if(!qiddonttouch)
  186. return Eperm;
  187. if(uname){
  188. if((server->openflags & LogfsOpenFlagWstatAllow) == 0)
  189. return Eperm;
  190. }
  191. if(muname)
  192. return Eperm;
  193. /*
  194. * we can do this
  195. */
  196. if(mtimedonttouch && permdonttouch && lengthdonttouch
  197. && name == nil && uname == nil && gname == nil) {
  198. /*
  199. * but we aren't doing anything - this is a wstat flush
  200. */
  201. return logfsserverflush(server);
  202. }
  203. if(name) {
  204. cname = logfsstrdup(name);
  205. if(cname == nil)
  206. return Enomem;
  207. }
  208. else
  209. cname = nil;
  210. /*
  211. * send the log message
  212. */
  213. s.type = LogfsLogTwstat;
  214. s.path = e->qid.path;
  215. s.u.wstat.name = cname;
  216. s.u.wstat.perm = perm;
  217. s.u.wstat.uid = nuid;
  218. s.u.wstat.gid = ngid;
  219. s.u.wstat.mtime = mtime;
  220. s.u.wstat.muid = cuid;
  221. errmsg = logfslog(server, 1, &s);
  222. if(errmsg) {
  223. logfsfreemem(cname);
  224. return errmsg;
  225. }
  226. if(!mtimedonttouch)
  227. e->mtime = mtime;
  228. if(!permdonttouch)
  229. e->perm = (e->perm & DMDIR) | perm;
  230. if(!lengthdonttouch) {
  231. /* TODO */
  232. }
  233. if(name) {
  234. logfsfreemem(e->name);
  235. e->name = cname;
  236. }
  237. if(uname)
  238. e->uid = nuid;
  239. if(ngid)
  240. e->gid = ngid;
  241. return nil;
  242. }