• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "proc_file.h"
33 #include <stdio.h>
34 #include <linux/errno.h>
35 #include <linux/module.h>
36 #include "internal.h"
37 #include "user_copy.h"
38 
39 #define MIN(a, b) ((a) < (b) ? (a) : (b))
40 #define PROC_ROOTDIR_NAMELEN   5
41 #define PROC_INUSE             2
42 
43 DEFINE_SPINLOCK(procfsLock);
44 bool procfsInit = false;
45 
46 static struct ProcFile g_procPf = {
47     .fPos       = 0,
48 };
49 
50 static struct ProcDirEntry g_procRootDirEntry = {
51     .nameLen     = 5,
52     .mode        = S_IFDIR | PROCFS_DEFAULT_MODE,
53     .count       = ATOMIC_INIT(1),
54     .procFileOps = NULL,
55     .parent      = &g_procRootDirEntry,
56     .name        = "/proc",
57     .subdir      = NULL,
58     .next        = NULL,
59     .pf          = &g_procPf,
60     .type        = VNODE_TYPE_DIR,
61 };
62 
ProcMatch(unsigned int len,const char * name,struct ProcDirEntry * pn)63 int ProcMatch(unsigned int len, const char *name, struct ProcDirEntry *pn)
64 {
65     if (len != pn->nameLen) {
66         return 0;
67     }
68     return !strncmp(name, pn->name, len);
69 }
70 
ProcFindNode(struct ProcDirEntry * parent,const char * name)71 static struct ProcDirEntry *ProcFindNode(struct ProcDirEntry *parent, const char *name)
72 {
73     struct ProcDirEntry *pn = NULL;
74     int length;
75 
76     if ((parent == NULL) || (name == NULL)) {
77         return pn;
78     }
79     length = strlen(name);
80 
81     for (pn = parent->subdir; pn != NULL; pn = pn->next) {
82         if ((length == pn->nameLen) && strcmp(pn->name, name) == 0) {
83             break;
84         }
85     }
86 
87     return pn;
88 }
89 
90 /*
91  * description: find the file's handle
92  * path: the file of fullpath
93  * return: the file of handle
94  * add by ll
95  */
ProcFindEntry(const char * path)96 struct ProcDirEntry *ProcFindEntry(const char *path)
97 {
98     struct ProcDirEntry *pn = NULL;
99     int isfoundsub;
100     const char *next = NULL;
101     unsigned int len;
102     int leveltotal = 0;
103     int levelcount = 0;
104     const char *p = NULL;
105     const char *name = path;
106 
107     while ((p = strchr(name, '/')) != NULL) {
108         leveltotal++;
109         name = p;
110         name++;
111     }
112     if (leveltotal < 1) {
113         return pn;
114     }
115 
116     spin_lock(&procfsLock);
117 
118     pn = &g_procRootDirEntry;
119 
120     while ((pn != NULL) && (levelcount < leveltotal)) {
121         levelcount++;
122         isfoundsub = 0;
123         while (pn != NULL) {
124             next = strchr(path, '/');
125             if (next == NULL) {
126                 while (pn != NULL) {
127                     if (strcmp(path, pn->name) == 0) {
128                         spin_unlock(&procfsLock);
129                         return pn;
130                     }
131                     pn = pn->next;
132                 }
133                 pn = NULL;
134                 spin_unlock(&procfsLock);
135                 return pn;
136             }
137 
138             len = next - path;
139             if (pn == &g_procRootDirEntry) {
140                 if (levelcount == leveltotal) {
141                     spin_unlock(&procfsLock);
142                     return pn;
143                 }
144                 len = g_procRootDirEntry.nameLen;
145             }
146             if (ProcMatch(len, path, pn)) {
147                 isfoundsub = 1;
148                 path += len + 1;
149                 break;
150             }
151 
152             pn = pn->next;
153         }
154 
155         if ((isfoundsub == 1) && (pn != NULL)) {
156             pn = pn->subdir;
157         } else {
158             pn = NULL;
159             spin_unlock(&procfsLock);
160             return pn;
161         }
162     }
163     spin_unlock(&procfsLock);
164     return NULL;
165 }
166 
CheckProcName(const char * name,struct ProcDirEntry ** parent,const char ** lastName)167 static int CheckProcName(const char *name, struct ProcDirEntry **parent, const char **lastName)
168 {
169     struct ProcDirEntry *pn = *parent;
170     const char *segment = name;
171     const char *restName = NULL;
172     int length;
173 
174     if (pn == NULL) {
175         pn = &g_procRootDirEntry;
176     }
177 
178     spin_lock(&procfsLock);
179 
180     restName = strchr(segment, '/');
181     for (; restName != NULL; restName = strchr(segment, '/')) {
182         length = restName - segment;
183         for (pn = pn->subdir; pn != NULL; pn = pn->next) {
184             if (ProcMatch(length, segment, pn)) {
185                 break;
186             }
187         }
188         if (pn == NULL) {
189             PRINT_ERR(" Error!No such name '%s'\n", name);
190             spin_unlock(&procfsLock);
191             return -ENOENT;
192         }
193         segment = restName;
194         segment++;
195     }
196     *lastName = segment;
197     *parent = pn;
198     spin_unlock(&procfsLock);
199 
200     return 0;
201 }
202 
ProcAllocNode(struct ProcDirEntry ** parent,const char * name,mode_t mode)203 static struct ProcDirEntry *ProcAllocNode(struct ProcDirEntry **parent, const char *name, mode_t mode)
204 {
205     struct ProcDirEntry *pn = NULL;
206     const char *lastName = NULL;
207     int ret;
208 
209     if ((name == NULL) || (strlen(name) == 0) || (procfsInit == false)) {
210         return pn;
211     }
212 
213     if (CheckProcName(name, parent, &lastName) != 0) {
214         return pn;
215     }
216 
217     if (strlen(lastName) > NAME_MAX) {
218         return pn;
219     }
220 
221     if ((S_ISDIR((*parent)->mode) == 0) || (strchr(lastName, '/'))) {
222         return pn;
223     }
224 
225     pn = (struct ProcDirEntry *)malloc(sizeof(struct ProcDirEntry));
226     if (pn == NULL) {
227         return NULL;
228     }
229 
230     if ((mode & S_IALLUGO) == 0) {
231         mode |= S_IRUSR | S_IRGRP | S_IROTH;
232     }
233 
234     (void)memset_s(pn, sizeof(struct ProcDirEntry), 0, sizeof(struct ProcDirEntry));
235     pn->nameLen = strlen(lastName);
236     pn->mode = mode;
237     ret = memcpy_s(pn->name, sizeof(pn->name), lastName, strlen(lastName) + 1);
238     if (ret != EOK) {
239         free(pn);
240         return NULL;
241     }
242 
243     pn->pf = (struct ProcFile *)malloc(sizeof(struct ProcFile));
244     if (pn->pf == NULL) {
245         free(pn);
246         return NULL;
247     }
248     (void)memset_s(pn->pf, sizeof(struct ProcFile), 0, sizeof(struct ProcFile));
249     pn->pf->pPDE = pn;
250     ret = memcpy_s(pn->pf->name, sizeof(pn->pf->name), pn->name, pn->nameLen + 1);
251     if (ret != EOK) {
252         free(pn->pf);
253         free(pn);
254         return NULL;
255     }
256 
257     atomic_set(&pn->count, 1);
258     spin_lock_init(&pn->pdeUnloadLock);
259     return pn;
260 }
261 
ProcAddNode(struct ProcDirEntry * parent,struct ProcDirEntry * pn)262 static int ProcAddNode(struct ProcDirEntry *parent, struct ProcDirEntry *pn)
263 {
264     struct ProcDirEntry *temp = NULL;
265 
266     if (parent == NULL) {
267         PRINT_ERR("%s(): parent is NULL", __FUNCTION__);
268         return -EINVAL;
269     }
270 
271     if (pn->parent != NULL) {
272         PRINT_ERR("%s(): node already has a parent", __FUNCTION__);
273         return -EINVAL;
274     }
275 
276     if (S_ISDIR(parent->mode) == 0) {
277         PRINT_ERR("%s(): parent is not a directory", __FUNCTION__);
278         return -EINVAL;
279     }
280 
281     spin_lock(&procfsLock);
282 
283     temp = ProcFindNode(parent, pn->name);
284     if (temp != NULL) {
285         PRINT_ERR("Error!ProcDirEntry '%s/%s' already registered\n", parent->name, pn->name);
286         spin_unlock(&procfsLock);
287         return -EEXIST;
288     }
289 
290     pn->parent = parent;
291     pn->next = parent->subdir;
292     parent->subdir = pn;
293 
294     spin_unlock(&procfsLock);
295 
296     return 0;
297 }
298 
ProcDetachNode(struct ProcDirEntry * pn)299 void ProcDetachNode(struct ProcDirEntry *pn)
300 {
301     struct ProcDirEntry *parent = pn->parent;
302     struct ProcDirEntry **iter = NULL;
303 
304     if (parent == NULL) {
305         PRINT_ERR("%s(): node has no parent", __FUNCTION__);
306         return;
307     }
308 
309     iter = &parent->subdir;
310     while (*iter != NULL) {
311         if (*iter == pn) {
312             *iter = pn->next;
313             break;
314         }
315         iter = &(*iter)->next;
316     }
317     pn->parent = NULL;
318 }
319 
ProcCreateDir(struct ProcDirEntry * parent,const char * name,const struct ProcFileOperations * procFileOps,mode_t mode)320 static struct ProcDirEntry *ProcCreateDir(struct ProcDirEntry *parent, const char *name,
321                                           const struct ProcFileOperations *procFileOps, mode_t mode)
322 {
323     struct ProcDirEntry *pn = NULL;
324     int ret;
325 
326     pn = ProcAllocNode(&parent, name, S_IFDIR | mode);
327     if (pn == NULL) {
328         return pn;
329     }
330     pn->procFileOps = procFileOps;
331     pn->type = VNODE_TYPE_DIR;
332     ret = ProcAddNode(parent, pn);
333     if (ret != 0) {
334         free(pn->pf);
335         free(pn);
336         return NULL;
337     }
338 
339     return pn;
340 }
341 
ProcCreateFile(struct ProcDirEntry * parent,const char * name,const struct ProcFileOperations * procFileOps,mode_t mode)342 static struct ProcDirEntry *ProcCreateFile(struct ProcDirEntry *parent, const char *name,
343                                            const struct ProcFileOperations *procFileOps, mode_t mode)
344 {
345     struct ProcDirEntry *pn = NULL;
346     int ret;
347 
348     pn = ProcAllocNode(&parent, name, S_IFREG | mode);
349     if (pn == NULL) {
350         return pn;
351     }
352 
353     pn->procFileOps = procFileOps;
354     pn->type = VNODE_TYPE_REG;
355 #ifdef LOSCFG_PROC_PROCESS_DIR
356     if (S_ISLNK(mode)) {
357         pn->type = VNODE_TYPE_VIR_LNK;
358     }
359 #endif
360     ret = ProcAddNode(parent, pn);
361     if (ret != 0) {
362         free(pn->pf);
363         free(pn);
364         return NULL;
365     }
366 
367     return pn;
368 }
369 
CreateProcEntry(const char * name,mode_t mode,struct ProcDirEntry * parent)370 struct ProcDirEntry *CreateProcEntry(const char *name, mode_t mode, struct ProcDirEntry *parent)
371 {
372     struct ProcDirEntry *pde = NULL;
373 
374     if (S_ISDIR(mode)) {
375         pde = ProcCreateDir(parent, name, NULL, mode);
376     } else {
377         pde = ProcCreateFile(parent, name, NULL, mode);
378     }
379     return pde;
380 }
381 
ProcEntryClearVnode(struct ProcDirEntry * entry)382 void ProcEntryClearVnode(struct ProcDirEntry *entry)
383 {
384     struct Vnode *item = NULL;
385     struct Vnode *nextItem = NULL;
386 
387     VnodeHold();
388     LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, GetVnodeActiveList(), struct Vnode, actFreeEntry) {
389         if ((struct ProcDirEntry *)item->data != entry) {
390             continue;
391         }
392 
393         if (VnodeFree(item) != LOS_OK) {
394             PRINT_ERR("ProcEntryClearVnode free failed, entry: %s\n", entry->name);
395         }
396     }
397     VnodeDrop();
398     return;
399 }
400 
FreeProcEntry(struct ProcDirEntry * entry)401 static void FreeProcEntry(struct ProcDirEntry *entry)
402 {
403     if (entry == NULL) {
404         return;
405     }
406 
407     if (entry->pf != NULL) {
408         free(entry->pf);
409         entry->pf = NULL;
410     }
411     if ((entry->dataType == PROC_DATA_FREE) && (entry->data != NULL)) {
412         free(entry->data);
413     }
414     entry->data = NULL;
415     free(entry);
416 }
417 
ProcFreeEntry(struct ProcDirEntry * pn)418 void ProcFreeEntry(struct ProcDirEntry *pn)
419 {
420     if (atomic_dec_and_test(&pn->count)) {
421         FreeProcEntry(pn);
422     }
423 }
424 
RemoveProcEntryTravalsal(struct ProcDirEntry * pn)425 void RemoveProcEntryTravalsal(struct ProcDirEntry *pn)
426 {
427     if (pn == NULL) {
428         return;
429     }
430     RemoveProcEntryTravalsal(pn->next);
431     RemoveProcEntryTravalsal(pn->subdir);
432 
433     ProcEntryClearVnode(pn);
434 
435     ProcFreeEntry(pn);
436 }
437 
RemoveProcEntry(const char * name,struct ProcDirEntry * parent)438 void RemoveProcEntry(const char *name, struct ProcDirEntry *parent)
439 {
440     struct ProcDirEntry *pn = NULL;
441     const char *lastName = name;
442 
443     if ((name == NULL) || (strlen(name) == 0) || (procfsInit == false)) {
444         return;
445     }
446 
447     if (CheckProcName(name, &parent, &lastName) != 0) {
448         return;
449     }
450 
451     spin_lock(&procfsLock);
452 
453     pn = ProcFindNode(parent, lastName);
454     if (pn == NULL) {
455         PRINT_ERR("Error:name '%s' not found!\n", name);
456         spin_unlock(&procfsLock);
457         return;
458     }
459     ProcDetachNode(pn);
460 
461     spin_unlock(&procfsLock);
462 
463     RemoveProcEntryTravalsal(pn->subdir);
464 
465     ProcEntryClearVnode(pn);
466 
467     ProcFreeEntry(pn);
468 }
469 
ProcMkdirMode(const char * name,mode_t mode,struct ProcDirEntry * parent)470 struct ProcDirEntry *ProcMkdirMode(const char *name, mode_t mode, struct ProcDirEntry *parent)
471 {
472     return ProcCreateDir(parent, name, NULL, mode);
473 }
474 
ProcMkdir(const char * name,struct ProcDirEntry * parent)475 struct ProcDirEntry *ProcMkdir(const char *name, struct ProcDirEntry *parent)
476 {
477     return ProcCreateDir(parent, name, NULL, 0);
478 }
479 
ProcCreateData(const char * name,mode_t mode,struct ProcDirEntry * parent,const struct ProcFileOperations * procFileOps,struct ProcDataParm * param)480 struct ProcDirEntry *ProcCreateData(const char *name, mode_t mode, struct ProcDirEntry *parent,
481                                     const struct ProcFileOperations *procFileOps, struct ProcDataParm *param)
482 {
483     struct ProcDirEntry *pde = CreateProcEntry(name, mode, parent);
484     if (pde != NULL) {
485         if (procFileOps != NULL) {
486             pde->procFileOps = procFileOps;
487         }
488         if (param != NULL) {
489             pde->data = param->data;
490             pde->dataType = param->dataType;
491         }
492     }
493     return pde;
494 }
495 
ProcCreate(const char * name,mode_t mode,struct ProcDirEntry * parent,const struct ProcFileOperations * procFileOps)496 struct ProcDirEntry *ProcCreate(const char *name, mode_t mode, struct ProcDirEntry *parent,
497                                 const struct ProcFileOperations *procFileOps)
498 {
499     return ProcCreateData(name, mode, parent, procFileOps, NULL);
500 }
501 
ProcStat(const char * file,struct ProcStat * buf)502 int ProcStat(const char *file, struct ProcStat *buf)
503 {
504     struct ProcDirEntry *pn = NULL;
505     int len = sizeof(buf->name);
506     int ret;
507 
508     pn = ProcFindEntry(file);
509     if (pn == NULL) {
510         return ENOENT;
511     }
512     ret = strncpy_s(buf->name, len, pn->name, len - 1);
513     if (ret != EOK) {
514         return ENAMETOOLONG;
515     }
516     buf->name[len - 1] = '\0';
517     buf->stMode = pn->mode;
518     buf->pPDE = pn;
519 
520     return 0;
521 }
522 
GetNextDir(struct ProcDirEntry * pn,void * buf,size_t len)523 static int GetNextDir(struct ProcDirEntry *pn, void *buf, size_t len)
524 {
525     char *buff = (char *)buf;
526 
527     if (pn->pdirCurrent == NULL) {
528         *buff = '\0';
529         return -ENOENT;
530     }
531     int namelen = pn->pdirCurrent->nameLen;
532     int ret = memcpy_s(buff, len, pn->pdirCurrent->name, namelen);
533     if (ret != EOK) {
534         return -ENAMETOOLONG;
535     }
536 
537     pn->pdirCurrent = pn->pdirCurrent->next;
538     pn->pf->fPos++;
539     return ENOERR;
540 }
541 
ProcOpen(struct ProcFile * procFile)542 int ProcOpen(struct ProcFile *procFile)
543 {
544     if (procFile == NULL) {
545         return PROC_ERROR;
546     }
547     if (procFile->sbuf != NULL) {
548         return OK;
549     }
550 
551     struct SeqBuf *buf = LosBufCreat();
552     if (buf == NULL) {
553         return PROC_ERROR;
554     }
555     procFile->sbuf = buf;
556     return OK;
557 }
558 
ProcRead(struct ProcDirEntry * pde,char * buf,size_t len)559 static int ProcRead(struct ProcDirEntry *pde, char *buf, size_t len)
560 {
561     if (pde == NULL || pde->pf == NULL) {
562         return PROC_ERROR;
563     }
564     struct ProcFile *procFile = pde->pf;
565     struct SeqBuf *sb = procFile->sbuf;
566 
567     if (sb->buf == NULL) {
568         // only read once to build the storage buffer
569         if (pde->procFileOps->read(sb, pde->data) != 0) {
570             return PROC_ERROR;
571         }
572     }
573 
574     size_t realLen;
575     loff_t pos = procFile->fPos;
576 
577     if ((pos >= sb->count) || (len == 0)) {
578         /* there's no data or at the file tail. */
579         realLen = 0;
580     } else {
581         realLen = MIN((sb->count - pos), MIN(len, INT_MAX));
582         if (LOS_CopyFromKernel(buf, len, sb->buf + pos, realLen) != 0) {
583             return PROC_ERROR;
584         }
585 
586         procFile->fPos = pos + realLen;
587     }
588 
589     return (ssize_t)realLen;
590 }
591 
OpenProcFile(const char * fileName,int flags,...)592 struct ProcDirEntry *OpenProcFile(const char *fileName, int flags, ...)
593 {
594     struct ProcDirEntry *pn = ProcFindEntry(fileName);
595     if (pn == NULL) {
596         return NULL;
597     }
598 
599     if (S_ISREG(pn->mode) && (pn->count != 1)) {
600         return NULL;
601     }
602 
603     pn->flags = (unsigned int)(pn->flags) | (unsigned int)flags;
604     atomic_set(&pn->count, PROC_INUSE);
605     if (ProcOpen(pn->pf) != OK) {
606         return NULL;
607     }
608     if (S_ISREG(pn->mode) && (pn->procFileOps != NULL) && (pn->procFileOps->open != NULL)) {
609         (void)pn->procFileOps->open((struct Vnode *)pn, pn->pf);
610     }
611     if (S_ISDIR(pn->mode)) {
612         pn->pdirCurrent = pn->subdir;
613         pn->pf->fPos = 0;
614     }
615 
616     return pn;
617 }
618 
ReadProcFile(struct ProcDirEntry * pde,void * buf,size_t len)619 int ReadProcFile(struct ProcDirEntry *pde, void *buf, size_t len)
620 {
621     int result = -EPERM;
622 
623     if (pde == NULL) {
624         return result;
625     }
626     if (S_ISREG(pde->mode)) {
627         if ((pde->procFileOps != NULL) && (pde->procFileOps->read != NULL)) {
628             result = ProcRead(pde, (char *)buf, len);
629         }
630     } else if (S_ISDIR(pde->mode)) {
631         result = GetNextDir(pde, buf, len);
632     }
633     return result;
634 }
635 
WriteProcFile(struct ProcDirEntry * pde,const void * buf,size_t len)636 int WriteProcFile(struct ProcDirEntry *pde, const void *buf, size_t len)
637 {
638     int result = -EPERM;
639 
640     if (pde == NULL) {
641         return result;
642     }
643 
644     if (S_ISDIR(pde->mode)) {
645         return -EISDIR;
646     }
647 
648     spin_lock(&procfsLock);
649     if ((pde->procFileOps != NULL) && (pde->procFileOps->write != NULL)) {
650         result = pde->procFileOps->write(pde->pf, (const char *)buf, len, &(pde->pf->fPos));
651     }
652     spin_unlock(&procfsLock);
653     return result;
654 }
655 
LseekProcFile(struct ProcDirEntry * pde,loff_t offset,int whence)656 loff_t LseekProcFile(struct ProcDirEntry *pde, loff_t offset, int whence)
657 {
658     if (pde == NULL || pde->pf == NULL) {
659         return PROC_ERROR;
660     }
661 
662     struct ProcFile *procFile = pde->pf;
663 
664     loff_t result = -EINVAL;
665 
666     switch (whence) {
667         case SEEK_CUR:
668             result = procFile->fPos + offset;
669             break;
670 
671         case SEEK_SET:
672             result = offset;
673             break;
674 
675         default:
676             break;
677     }
678 
679     if (result >= 0) {
680         procFile->fPos = result;
681     }
682 
683     return result;
684 }
685 
LseekDirProcFile(struct ProcDirEntry * pde,off_t * pos,int whence)686 int LseekDirProcFile(struct ProcDirEntry *pde, off_t *pos, int whence)
687 {
688     /* Only allow SEEK_SET to zero */
689     if ((whence != SEEK_SET) || (*pos != 0)) {
690         return EINVAL;
691     }
692     pde->pdirCurrent = pde->subdir;
693     pde->pf->fPos = 0;
694     return ENOERR;
695 }
696 
CloseProcFile(struct ProcDirEntry * pde)697 int CloseProcFile(struct ProcDirEntry *pde)
698 {
699     int result = 0;
700 
701     if (pde == NULL) {
702         return -EPERM;
703     }
704     pde->pf->fPos = 0;
705     atomic_set(&pde->count, 1);
706     if (S_ISDIR(pde->mode)) {
707         pde->pdirCurrent = pde->subdir;
708     }
709 
710     if ((pde->procFileOps != NULL) && (pde->procFileOps->release != NULL)) {
711         result = pde->procFileOps->release((struct Vnode *)pde, pde->pf);
712     }
713     LosBufRelease(pde->pf->sbuf);
714     pde->pf->sbuf = NULL;
715 
716     if (pde->parent == NULL) {
717         FreeProcEntry(pde);
718     }
719     return result;
720 }
721 
GetProcRootEntry(void)722 struct ProcDirEntry *GetProcRootEntry(void)
723 {
724     return &g_procRootDirEntry;
725 }
726